首頁  >  文章  >  Java  >  Java反射是什麼? Java反射機制的詳細介紹

Java反射是什麼? Java反射機制的詳細介紹

不言
不言原創
2018-09-19 14:30:161965瀏覽

這篇文章帶給大家的內容是關於Java反射是什麼? Java反射機制的詳細介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

一、概念

    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 的反射機制,我新建了一對父子類,其中涵蓋了四種封裝屬性,以盡可能的測試多種類資訊的獲取:

Vehicle.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;
    }
}

Car.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;
    }
}

#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 類別對建構方法的取得主要透過以下兩種方式:

Constructor6b3d0130bba23ae47fe2b8e8cddf0195[ ] getConstructors() :傳回該類別或介面的所有的公共建構方法

Constructor6b3d0130bba23ae47fe2b8e8cddf0195[] 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));
    }
}

以上是Java反射是什麼? Java反射機制的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn