• Java反射


    目录

    1.反射相关的主要API
    2.通过反射机制获取类的三种方法
    2.1 Class.forName()
    2.2 getClass()
    2.3 使用类字面常量来生成对Class对象的引用(例如 Example.class)
    3.获取某个类的所有构造方法
    4.获取某个类的所有属性信息
    5.获取某个类的所有方法信息

    在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

    程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
    Perl、Python、Ruby是动态语言;C++、Java、C#不是动态语言。
    Java程序可以加载一个运行时才得知名称的class,获悉其完整构造,并生成其对象实体,或对其fields设值,或唤起其methods。
    反射主要有两个重要功能:
    1.可以通过反射机制发现对象的类型,发现类型的方法、属性、构造器。
    2.可以创建对象并访问任意对象方法和属性等。

    Class类的实例表示正在运行的Java应用程序的类和接口。
    通过Class实例可以获取某个类的属性(Field)、构造器(Constructor)、方法(Method)。
    程序可以通过Method对象来执行对应的方法,通过Constructor对象来调用对应的构造器创建实例,能通过Field对象直接访问并修改对象的属性值。

    1.反射相关的主要API

    • java.lang.Class
    • java.lang.reflect.Method
    • java.lang.reflect.Field
    • java.lang.reflect.Constructor

    Class类与java.lang.reflect类库一起对反射的概念进行了支持。该类库包含了Field、Method以及Constructor类(每个类都实现了Member接口)。这些类型的对象是由JVM在运行时创建的。

    2.通过反射机制获取类的三种方法

    每个类都有一个Class对象。
    一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

    2.1 Class.forName()

    Class.forName()是取得Class对象的引用的一种方法。
    只要你想在运行时使用类型信息,就必须首先获得对恰当的Class对象的引用。
    使用Class.forName(),你不需要为了获得Class引用而持有该类型的对象。

    class Candy {
      static { System.out.println("Loading Candy"); }
    }
    
    class Gum {
      static { System.out.println("Loading Gum"); }
    }
    
    class Cookie {
      static { System.out.println("Loading Cookie"); }
    }
    
    public class SweetShop {
      public static void main(String[] args) {  
        System.out.println("inside main");
        new Candy();
        System.out.println("After creating Candy");
        try {
          Class.forName("Gum");
        } catch(ClassNotFoundException e) {
          System.out.println("Couldn't find Gum");
        }
        System.out.println("After Class.forName("Gum")");
        new Cookie();
        System.out.println("After creating Cookie");
      }
    }
     

    输出结果:

    inside main
    Loading Candy
    After creating Candy
    Loading Gum
    After Class.forName("Gum")
    Loading Cookie
    After creating Cookie
     

    注意:在传递给Class.forName()的字符串中,你必须使用全限定名(包含包名)。

    2.2 getClass()

    如果你已经拥有一个类型的对象,那就可以通过调用getClass()方法来获取Class引用了。

    package typeinfo.toys;
    
    interface HasBatteries {}
    interface Waterproof {}
    interface Shoots {}
    
    class Toy {
      // Comment out the following default constructor
      // to see NoSuchMethodError from (*1*)
      Toy() {}
      Toy(int i) {}
    }
    
    class FancyToy extends Toy
    implements HasBatteries, Waterproof, Shoots {
      FancyToy() { super(1); }
    }
    
    public class ToyTest {
      static void printInfo(Class cc) {
        System.out.println("Class name: " + cc.getName() +
          " is interface? [" + cc.isInterface() + "]");
        System.out.println("Simple name: " + cc.getSimpleName());
        System.out.println("Canonical name : " + cc.getCanonicalName());
      }
      public static void main(String[] args) {
        Class c = null;
        try {
          c = Class.forName("typeinfo.toys.FancyToy");
        } catch(ClassNotFoundException e) {
          System.out.println("Can't find FancyToy");
          System.exit(1);
        }
        printInfo(c);   
        for(Class face : c.getInterfaces())
          printInfo(face);
        Class up = c.getSuperclass();
        Object obj = null;
        try {
          // Requires default constructor:
          obj = up.newInstance();
        } catch(InstantiationException e) {
          System.out.println("Cannot instantiate");
          System.exit(1);
        } catch(IllegalAccessException e) {
          System.out.println("Cannot access");
          System.exit(1);
        }
        printInfo(obj.getClass());
      }
    }
     

    输出结果:

    Class name: typeinfo.toys.FancyToy is interface? [false]
    Simple name: FancyToy
    Canonical name : typeinfo.toys.FancyToy
    Class name: typeinfo.toys.HasBatteries is interface? [true]
    Simple name: HasBatteries
    Canonical name : typeinfo.toys.HasBatteries
    Class name: typeinfo.toys.Waterproof is interface? [true]
    Simple name: Waterproof
    Canonical name : typeinfo.toys.Waterproof
    Class name: typeinfo.toys.Shoots is interface? [true]
    Simple name: Shoots
    Canonical name : typeinfo.toys.Shoots
    Class name: typeinfo.toys.Toy is interface? [false]
    Simple name: Toy
    Canonical name : typeinfo.toys.Toy
     

    下面的代码片段就是通过getClass()来获取Class引用的。

    Class的newInstance()方法表明:“我不知道你的确切类型,但是无论如何要正确地创建你自己”。
    使用newInstance()来创建的类,必须带有默认的构造器。

    2.3 使用类字面常量来生成对Class对象的引用(例如 Example.class)

    类字面常量不仅可以用于普通的类,也可以应用于接口、数组以及基本数据类型。
    对于基本数据类型的包装类,还有一个标准字段TYPE。
    TYPE字段是一个引用,指向对应的基本数据类型的Class对象。

    当使用“.class”来创建对Class对象的引用时,不会自动地初始化该Class对象。
    为了使用类而做的准备工作实际包含三个步骤:

    1. 加载。这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必需的),并从这些字节码中创建一个Class对象。
    2. 链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
    3. 初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。

    初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。

    class Initable {
      static final int staticFinal = 47;
      static final int staticFinal2 =
        ClassInitialization.rand.nextInt(1000);
      static {
        System.out.println("Initializing Initable");
      }
    }
    
    class Initable2 {
      static int staticNonFinal = 147;
      static {
        System.out.println("Initializing Initable2");
      }
    }
    
    class Initable3 {
      static int staticNonFinal = 74;
      static {
        System.out.println("Initializing Initable3");
      }
    }
    
    public class ClassInitialization {
      public static Random rand = new Random(47);
      public static void main(String[] args) throws Exception {
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        // Does not trigger initialization:
        System.out.println(Initable.staticFinal);
        // Does trigger initialization:
        System.out.println(Initable.staticFinal2);
        // Does trigger initialization:
        System.out.println(Initable2.staticNonFinal);
        Class initable3 = Class.forName("Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
      }
    }
    
    输出结果:
    
    After creating Initable ref
    47
    Initializing Initable
    258
    Initializing Initable2
    147
    Initializing Initable3
    After creating Initable3 ref
    74
    
    3.获取某个类的所有构造方法
    
    public class ReflectTest1 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            String className = cc.getName();
            System.out.println(className);
            Constructor[] declaredConstructors = cc.getDeclaredConstructors();
            for (Constructor constructor : declaredConstructors) {
                int modifiers = constructor.getModifiers();
                System.out.print(Modifier.toString(modifiers) + " ");
                System.out.print(constructor.getName() + "(");
                Class[] paramTypes = constructor.getParameterTypes();
                for (Class paramType : paramTypes) {
                    System.out.print(paramType.getName() + " ");
                }
                System.out.println(")");
            }
        }
    }

    输出结果:

    java.util.Date
    public java.util.Date(java.lang.String )
    public java.util.Date(int int int int int int )
    public java.util.Date(int int int int int )
    public java.util.Date()
    public java.util.Date(long )
    public java.util.Date(int int int )

    4.获取某个类的所有属性信息

    public class ReflectTest2 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            String className = cc.getName();
            System.out.println(className);
            Field[] fields = cc.getDeclaredFields();
            for (Field field : fields) {
                String modifiers = Modifier.toString(field.getModifiers());
                Class type = field.getType();
                String name = field.getName();
                System.out.println(modifiers + " " + type.getName() + " " + name);
            }
        }
    }
     

    输出结果:

    java.util.Date
    private static final sun.util.calendar.BaseCalendar gcal
    private static sun.util.calendar.BaseCalendar jcal
    private transient long fastTime
    private transient sun.util.calendar.BaseCalendar$Date cdate
    private static int defaultCenturyStart
    private static final long serialVersionUID
    private static final [Ljava.lang.String; wtb
    private static final [I ttb
     

    5.获取某个类的所有方法信息

    public class ReflectTest3 {
        public static void main(String[] args) {
            Date date = new Date();
            Class cc = date.getClass();
            Method[] methods = cc.getDeclaredMethods();
            for (Method method : methods) {
                String modifiers = Modifier.toString(method.getModifiers());
                Class returnType = method.getReturnType();
                String name = method.getName();
                Class[] parameterTypes = method.getParameterTypes();
                Class[] exceptions = method.getExceptionTypes();
                System.out.println(modifiers + " " + returnType + " " + name
                        + "(" + Arrays.asList(parameterTypes) + ")throws" + Arrays.asList(exceptions));
            }
        }
    }
     

    输出结果:

    public boolean after([class java.util.Date])throws[]
    public boolean before([class java.util.Date])throws[]
    public boolean equals([class java.lang.Object])throws[]
    public class java.lang.String toString([])throws[]
    public int hashCode([])throws[]
    public class java.lang.Object clone([])throws[]
    public volatile int compareTo([class java.lang.Object])throws[]
    public int compareTo([class java.util.Date])throws[]
    ······
     
  • 相关阅读:
    屡获大奖的界面控件开发包DevExpress v22.1官宣发布
    界面控件Telerik UI for WinForms入门指南 使用VS扩展自动依赖解析
    行业领先的界面组件包DevExpress 6月正式发布v21.2.8
    UI组件库Kendo UI for Vue中文入门指南(四)
    B/S端界面组件DevExtreme Angular应用模板——新的身份验证UI
    界面开发组件DevExpress ASP.NET Core v21.2 UI组件增强
    UI组件库Kendo UI for Vue中文入门指南(三)
    看如何使用界面控件DevExpress WinForms完成win 11皮肤选项设置
    界面控件DevExpress WPF即将拥有Windows 11新主题
    界面组件DevExpress ASP.NET Core v21.2 流程图、甘特图增强
  • 原文地址:https://www.cnblogs.com/cl-rr/p/8998292.html
Copyright © 2020-2023  润新知