Java反射

Java反射

\color{red}{GitHub连接}

1.Class 类

  • 类是对象,类是java.lang.Class类的实例对象java

    public class MyClass {
        public static void main(String[] args) {
            // People的实例对象
            People people = new People();
            // 任何一个类,都是java.lang.Class的实例对象
        }
    }
    // People自己就是一个对象,是java.lang.Class的对象
    class People { }
    复制代码
  • Class类的三种表达方式android

    Class c1 = People.class;
    // 方法2:经过已知类对象的getClass方法
    Class c2 = people.getClass();
    // 方法3:经过Class类静态方法forName()
    Class c3 = Class.forName("com.nj.reflect.People");
    
    /* * c一、c2表示了People类的类类型(class type) * 类也是对象,是Class类的实例对象,这个对象咱们称为该类的类类型 */
    // 无论是c一、c2仍是c3都表明People的类类型,一个类只多是Class类的一个实例对象。
    System.out.print(c1 == c2); // true
    System.out.print(c1 == c3); // true
    复制代码
  • 获取对象实例git

    // 经过People类的类类型c一、c2或c3建立该类的实例对象。
    People people1 = (People) c1.newInstance(); // 须要有无参构造方法
    复制代码

2.动态加载类

  • Class.forName("类的全称")github

    • 不只表示了类的类类型,还表明了动态加载类
    • 编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。
  • 静态加载类数组

    public class Animal {
        public static void main(String[] args) {
            if (args[0].equals("Dog")) {
                Dog dog = new Dog();
                dog.eat();
            }
            if (args[0].equals("Cat")) {
                Cat cat = new Cat();
                cat.eat();
            }
        }
    }
    class Dog {
        public void eat() { }
    }
    class Cat {
        public void eat() { }
    }
    复制代码
    • 静态加载类的缺点ide

      1.若是Dog或者Cat不存在,会报错。可是Dog和Cat不必定会使用。函数

      2.经过new建立对象是静态加载类,在编译时刻,就须要加载全部可能使用到的类。spa

  • 动态加载类code

    经过Class.forName()动态加载类,就不会在编译时报错了。对象

    public class AnimalManager {
        public static void main(String[] args){
            try {
                // 动态加载类,在运行时刻加载。编译不会再报错。
                Class c = Class.forName(args[0]);
                // 建立对象,经过类类型建立该类的对象
                Object o = c.newInstance();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

    可是咱们经过c.newInstance()建立类对象的时候,问题来了,是该转换成Dog,仍是该转换成Cat。因此,须要统一标准,建立Animals接口,使Dog和Cat都实现Animals接口。

    public class AnimalManager {
        public static void main(String[] args){
            try {
                // 动态加载类,在运行时刻加载。编译不会再报错。
                Class c = Class.forName(args[0]);
                // 建立对象,经过类类型建立该类的对象
                Animals animals = (Animals) c.newInstance();
                animals.eat();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    interface Animals{
        void eat();
    }
    class Dog implements Animals{
        @Override
        public void eat() {}
    }
    class Cat implements Animals{
        @Override
        public void eat() {}
    }
    复制代码
    • 优势

      1.动态加载,更加灵活

      2.方便拓展,若是想要加个Pig类,直接建立Pig类,实现Animals接口和方法便可,无需再修改AnimalManager类。

3.反射的使用

  • 获取class对象的相关信息

    1.获取class对象的成员变量

    // 获取class1对象的全部成员变量,不包括父类的成员变量
    Field[] allFields = class1.getDeclaredFields();
    // 获取class1对象的public成员变量,包括父类里面的成员变量
    Field[] publicFields = class1.getFields();
    // 获取class1对象指定的成员变量,父类的没法获取
    Field name1 = class1.getDeclaredField("name");
    // 获取class1对象指定的public成员变量,包括查找父类
    Field name2 = class1.getField("name");
    
    // 获取变量的名称
    String name = field.getName();
    // 获取变量的类型
    Class type = field.getType();
    复制代码

    2.获取class对象的方法

    // 获取class1对象的全部方法,不包括父类的方法
    Method[] allMethods = class1.getDeclaredMethods();
    // 获取class1对象的public方法,包括父类的public方法
    Method[] publicMethods = class1.getMethods();
    // 获取class1对象指定的方法,父类的没法获取
    Method method1 = class1.getDeclaredMethod("getName");
    // 获取class1对象指定的方法,而且有一个int类型参数的方法
    Method method2 = class1.getDeclaredMethod("getName", int.class);
    // 获取class1对象有两个参数的指定方法
    Method method3 = class1.getDeclaredMethod("getName", int.class, String.class);
    // 获取class1对象指定的public方法,包括父类的public方法。
    Method method4 = class1.getMethod("getName");
    复制代码

    3.获取class对象的构造函数

    // 获取class1对象全部的构造函数
    Constructor[] allConstructors = class1.getDeclaredConstructors();
    // 获取class1对象public的构造函数
    Constructor[] publicConstructors = class1.getConstructors();
    // 获取class1对象指定参数的构造函数
    Constructor constructor1 = class1.getDeclaredConstructor(int.class);
    // 获取class1对象指定参数而且为public的构造函数
    Constructor constructor2 = class1.getConstructor(int.class, String.class);
    复制代码

    4.class对象的其余方法

    Annotation[] annotations = class1.getAnnotations();// 获取class对象的全部注解
    Annotation annotation = class1.getAnnotation(Override.class);// 获取class对象指定注解
    Class superclass = class1.getSuperclass(); // 获取class对象直接父类的类对象
    Type genericSuperclass = class1.getGenericSuperclass(); // 获取class对象的直接父类的Type
    Type[] genericInterfaces = class1.getGenericInterfaces(); // 获取class对象全部接口的Type集合
    String name = class1.getName(); // 获取class对象名称,包括报名路径
    String simpleName = class1.getSimpleName(); // 获取class类名
    Package aPackage = class1.getPackage(); // 获取class包信息
    boolean annotation = class1.isAnnotation();// 判断是否为注解类
    boolean anEnum = class1.isEnum();// 判断是否为枚举
    boolean anInterface = class1.isInterface();// 判断是否为接口类
    boolean array = class1.isArray();//判断是否为集合类型
    boolean primitive = class1.isPrimitive(); // 判断是否为原始类型(8个基础类型)
    boolean anonymousClass = class1.isAnonymousClass(); // 判断是不是匿名内部类
    boolean annotation1 = class1.isAnnotationPresent(Override.class);//判断是否被某个注解类修饰
    复制代码

    5.Method的相关方法

    Method method = class1.getMethod("getName", String.class);
    String name = method.getName(); // 获取方法名称
    // 获取方法的返回值类型的类类型
    Class returnType = method.getReturnType();
    // 获取方法的参数列表类型的类类型的数组
    Class[] parameterTypes = method.getParameterTypes();
    复制代码
  • Java反射的使用

    1.生成来的实例对象

    // 方法一:调用newInstance()方法,可是这个方法要求class1的类必须有无参构造函数。
    Dog dog = (Dog) class1.newInstance();
    // 方法二:经过getConstructor获取有参的Constructor构造函数,再调用newInstance()建立实例
    Constructor constructor = class1.getConstructor(String.class);
    Dog dog1 = (Dog) constructor.newInstance("dog");
    复制代码

    2.调用类的方法

    // 第一步:生成类对象
    Dog dog = (Dog) class1.newInstance();
    // 第二步:经过class对象的getMethod()等方法,得到具体须要执行的Method对象。
    Method method = class1.getDeclaredMethod("getName", String.class);
    // 若是方法是private修饰,直接调用invoke,会报错,Java要求程序必须有调用该方法的权限。
    // 调用setAccessible,并将参数设置为true,就会取消Java语言的访问权限检查。
    method.setAccessible(true);
    // 调用Method对象的invoke方法,第一个参数是调用该方法的实例对象,第二个参数是对应须要传入的参数。
    // invoke的返回值:若是方法的返回值为void,则invoke返回null,若是不是void,则返回具体的返回值
    // 至关于 dog.getName("dog");
    Object o = method.invoke(dog, "dog");
    复制代码

    3.访问成员变量的值

    // 第一步:生成类对象
    Dog dog = (Dog) class1.newInstance();
    // 第二步:经过getDeclaredField等方法,获取相应的Field对象
    Field field = class1.getDeclaredField("age");
    // 取消Java权限检查
    field.setAccessible(true);
    // 获取dog对象中age成员变量的值
    int age = field.getInt(dog);
    // 修改dog对象中age成员变量的值
    field.setInt(dog, 25);
    // 获取dog对象中String类型的成员变量
    Field field1 = class1.getDeclaredField("name");
    // 取消Java权限检查
    field1.setAccessible(true);
    // 获取name变量的值
    Object o = field1.get(dog);
    // 修改name变量的值
    field1.set(dog, "sam");
    复制代码

参考资料

1.Java反射

相关文章
相关标签/搜索