继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java 反射机制

慕沐林林
关注TA
已关注
手记 226
粉丝 29
获赞 116

一、概念

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

回到顶部

二、Class 类

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

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

复制代码

public class TestClass {    
    public static void main(String[] args) throws ClassNotFoundException {        // 1、 Class.forName();
        Class<?> aClass0 = Class.forName("java.lang.Object");        // 2、类名.Class
        Class<Integer> aClass1 = Integer.class;        // 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());
    }
}

复制代码

回到顶部

三、获取类信息

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

复制代码

vpublic class Vehicle {    private String color;    protected Integer seat;    int year;    public Date createdOn;    private String getColor() {        return color;
    }    protected Integer getSeat() {        return seat;
    }    int getYear() {        return year;
    }    public Date getCreatedOn() {        return createdOn;
    }
}

复制代码

Vehicle.java

复制代码

public class Car extends Vehicle {    private String brand;    protected Integer a;    int b;    public Date updatedOn;    public Car(){}    private Car(String brand, Integer a, int b, Date updatedOn) {        this.brand = brand;        this.a = a;        this.b = b;        this.updatedOn = updatedOn;
    }    private String getBrand() {        return brand;
    }    protected Integer getA() {        return a;
    }    int getB() {        return b;
    }    public Date getUpdatedOn() {        return updatedOn;
    }
}

复制代码

Car.java

    1、获取方法

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

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

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

复制代码

public class TestMethod {    public static void main(String[] args) {
        Class<Car> carClass = Car.class;
        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():存放该类或接口的所有属性(不含继承的属性)。

复制代码

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

复制代码

    3、获取构造函数

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

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

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

复制代码

public class TestConstructor {    public static void main(String[] args) throws NoSuchMethodException {
        Class<Car> carClass = Car.class;
        Constructor<?>[] constructors = carClass.getConstructors();
        Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
        Constructor<Car> carConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);        //for (Constructor constructor : declaredConstructors) {
        for (Constructor constructor : constructors) {
            System.out.println("该构造器的名称是:" + constructor.getName());
            System.out.println("该构造器所在的类或接口是:" + constructor.getDeclaringClass());            //返回构造方法的参数类型            constructor.getParameterTypes();
        }
    }
}

复制代码

回到顶部

四、动态调用

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

复制代码

public class Test {    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class<Car> carClass = Car.class;        // 1、实例化对象        // 调用 Class 类的newInstance();要求对应类必须有无参构造函数,相当于 Car car = new Car()
        Car car = carClass.newInstance();        // 调用构造器的newInstance(Object ... initargs);
        Constructor<Car> declaredConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);        // 取消访问权限控制,即使是 private 权限也可以访问
        declaredConstructor.setAccessible(true);
        Car car1 = declaredConstructor.newInstance("brand", 21, 21, new Date());
        System.out.println(car1.getUpdatedOn());        // 2、修改属性
        Field brand = carClass.getDeclaredField("brand");
        brand.setAccessible(true);
        System.out.println("取消访问权限控制后的值:" + brand.get(car1));
        brand.set(car1, "dnarb");
        System.out.println("修改属性后的值是:" + brand.get(car1));        // 3、调用方法
        Method getBrand = carClass.getDeclaredMethod("getBrand");
        getBrand.setAccessible(true);
        System.out.println("调用反射方法得到的值是:" + getBrand.invoke(car1));
    }
}

复制代码

原文出处:https://www.cnblogs.com/jmcui/p/9650710.html  

打开App,阅读手记
2人推荐
发表评论
随时随地看视频慕课网APP