Java 反射机制

一、概念

    Java 反射(Reflection)就是 Java 程序在运行时可以加载一个才知道类名的类,获得类的完整构造方法,并实例化出对象,给对象属性设定值或者调用对象的方法。这种在运行时动态获取类的信息以及动态调用对象的方法的功能称为 Java 的反射机制。

二、Class 类

    Class 类继承自 Object 类,是 Java 反射机制的入口,封装了一个类或接口的运行时信息,通过调用 Class 类的方法可以获取到这些信息。怎么理解这个 Class 类呢?如果说普通类是所有对象方法、属性的集合,那就可以把这个 Class 类理解成是所有普通类的集合。

    下面列举了获取 Class 类的几种方法:

public class TestClass {
    
    static void main(String[] args) throws ClassNotFoundException {
        // 1、 Class.forName();
        Class<?> aClass0 = Class.forName("java.lang.Object");
         2、类名.Class
        Class<Integer> aClass1 = Integer.;
         3、包装类.TYPE —— 返回基本类型的 Class 引用,基本类型在虚拟机运行时就已经加载了它的Class
        Class<Integer> aClass2 = Integer.TYPE;
         4、对象名.getClass()
        String str = "Hello,World";
        Class<? extends String> aClass3 = str.getClass();
         5、Class类.getSuperClass() —— 获得父类的 Class 对象
        Class<?> aClass4 = aClass3.getSuperclass();

        System.out.println(aClass0.getName());
        System.out.println(aClass1.getName());
        System.out.println(aClass2.getName());
        System.out.println(aClass3.getName());
        System.out.println(aClass4.getName());
    }
}
  1. aClass.isPrimitive(); //判断 aClass 是否为基本数据类型
  2. aClass.isAssignableFrom(ArrayList.class);  //判断 aClass 是否是 ArrayList 类的父类
  3. aClass.getGenericType(); //得到泛型类型

三、获取类信息

    为了测试 Java 的反射机制,我新建了一对父子类,其中涵盖了四种封装属性,以尽可能的测试多种类信息的获取:

vpublic  Vehicle {

    private String color;
    protected Integer seat;
    int year;
    public Date createdOn;

     String getColor() {
        return color;
    }

     Integer getSeat() {
         seat;
    }

     getYear() {
         year;
    }

     Date getCreatedOn() {
         createdOn;
    }
}
Vehicle.java

class Car extends String brand;
     Integer a;
     b;
     Date updatedOn;

     Car(){}

    private Car(String brand,Integer a, b,Date updatedOn) {
        this.brand = brand;
        this.a = a;
        this.b = b;
        this.updatedOn = updatedOn;
    }

     String getBrand() {
         brand;
    }

     Integer getA() {
         a;
    }

     getB() {
         b;
    }

     Date getUpdatedOn() {
         updatedOn;
    }
}
Car.java

    1、获取方法

        Class 类对方法的获取主要通过以下两种方式:

    Method[] getMethods() 返回该类或接口的所有可访问公共方法(含继承的公共方法)。

    Method[] getDeclaredMethods() 返回该类或接口的所有方法(不含继承的方法)。

 TestMethod {

    void main(String[] args) {
        Class<Car> carClass = Car.;
        Method[] methods = carClass.getMethods();
        Method[] declaredMethods = carClass.getDeclaredMethods();

        for (Method method : methods) {
        for (Method method : declaredMethods) {
            System.out.println("方法名:" + method.getName());
            System.out.println("该方法所在的类或接口:" + method.getDeclaringClass());
            System.out.println("该方法的参数列表:" + method.getParameterTypes());
            System.out.println("该方法的异常列表:" + method.getExceptionTypes());
            System.out.println("该方法的返回值类型:" + method.getReturnType());
        }
    }
}

    2、获取属性

        Class 类对属性的获取主要通过以下两种方式:

    Field[] getFields() :存放该类或接口的所有可访问公共属性(含继承的公共属性)。

    Field[] getDeclaredFields():存放该类或接口的所有属性(不含继承的属性)。

 TestField {

    ;
        Field[] fields = carClass.getFields();
        Field[] declaredFields = carClass.getDeclaredFields();
        for (Field field : fields) {
         (Field field : declaredFields) {
            System.out.println("属性名称是:" + field.getName());
            System.该属性所在的类或接口是: field.getDeclaringClass());
            System.该属性的类型是: field.getType());
             field.getModifiers() 以整数形式返回由此 Field 对象表示的属性的 Java 访问权限修饰符
            System.该属性的修饰符是: Modifier.toString(field.getModifiers()));
        }
    }
}

    3、获取构造函数

         Class 类对构造方法的获取主要通过以下两种方式:

    Constructor<?>[] getConstructors() :返回该类或接口的所有的公共构造方法

    Constructor<?>[] getDeclaredConstructors():返回该类或接口的所有构造方法

 TestConstructor {

     NoSuchMethodException {
        Class<Car> carClass = Car.;
        Constructor<?>[] constructors = carClass.getConstructors();
        Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
        Constructor<Car> carConstructor = carClass.getDeclaredConstructor(String.class,Integer.);

        for (Constructor constructor : declaredConstructors) {
         (Constructor constructor : constructors) {
            System.out.println("该构造器的名称是:" + constructor.getName());
            System.out.println("该构造器所在的类或接口是:" + constructor.getDeclaringClass());
            返回构造方法的参数类型
            constructor.getParameterTypes();
        }
    }
}

四、动态调用

    到目前为止,我们都是通过 Class 类的方法获取对应类属性、方法和构造函数的详细信息。接下来我们将通过这些信息,来动态创建对象、修改属性和动态调用方法。

 Test {

     IllegalAccessException,InstantiationException,NoSuchMethodException,InvocationTargetException,NoSuchFieldException {
        Class<Car> carClass = Car. 1、实例化对象
         调用 Class 类的newInstance();要求对应类必须有无参构造函数,相当于 Car car = new Car()
        Car car = carClass.newInstance();
         调用构造器的newInstance(Object ... initargs);
        Constructor<Car> declaredConstructor = carClass.getDeclaredConstructor(String. 取消访问权限控制,即使是 private 权限也可以访问
        declaredConstructor.setAccessible(true);
        Car car1 = declaredConstructor.newInstance("brand",21,1)">new Date());
        System.out.println(car1.getUpdatedOn());

         2、修改属性
        Field brand = carClass.getDeclaredField("brand");
        brand.setAccessible();
        System.out.println("取消访问权限控制后的值:" + brand.get(car1));
        brand.set(car1,"dnarb");
        System.out.println("修改属性后的值是:" + brand.get(car1));

         3、调用方法
        Method getBrand = carClass.getDeclaredMethod("getBrand");
        getBrand.setAccessible();
        System.out.println("调用反射方法得到的值是:" + getBrand.invoke(car1));
    }
}

相关文章

摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠...
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠...
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个...
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:...
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程...