JAVA反射機制

JAVA反射機制

咱們知道JAVA中一個比較重要的特性就是反射機制,那麼反射到底是什麼,咱們又能用反射作些什麼呢?今天咱們就來一探究竟。java

反射的概念

反射:將類的各個組成部分封裝爲其餘對象,這就是反射機制。框架

反射的做用:函數

一、在程序運行時操做這些對象;this

應用示例:IDEA中定義一個list對象,在使用「list.」時,會彈出對應的方法,這個就是利用反射,在IDEA運行時,就能知道對象list的成員方法;
image-20200516201709262.png編碼

二、能夠解耦,提升程序的可擴展性;spa

講到這裏,咱們可能還很迷惑,JAVA的反射機制到底是什麼?在進行下面的講解前,咱們先了解一下JAVA代碼在計算機中的三個階段,來幫助咱們理解反射機制。code

JAVA程序在計算機中的三個階段

image-20200516194635658.png

一、第一個階段:源代碼階段也就是咱們寫的JAVA代碼,經過編譯器編譯成字節碼文件這個過程,咱們寫的類含有成員變量,構造方法,成員方法;對象

二、第二個階段:類加載器將咱們的字節碼文件加載到內存,生成Class類對象(Class類封裝一個對象和接口運行時的狀態,當裝載類時,Class類型的對象自動建立)。反射定義中的」封裝爲其餘對象「,這裏的對象即是指,成員變量封裝爲Filed對象,構造方法封裝爲Constructor對象以及成員方法封裝爲Method對象blog

三、第三個階段:該階段就能夠建立對象和調用對象裏的方法。經過new Student()建立對象。接口

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。簡單來講就是獲得Class對象後反向獲取Student對象的各類信息。

獲取Class對象的方式:

對應java代碼在程序中的三個階段:
image-20200516211903426.png

一、Class.forName("全類名"):將字節碼文件加載進內存,返回Class對象;

使用場景:多用於配置文件,將全類名配置到配置文件中,經過讀取配置文件加載類;

二、類名.class :經過類名的屬性Class獲取;

使用場景:多用於參數傳遞;

三、對象.getClass():經過類的getClass方法獲取,getClass()方法在Object類中定義,全部的類都有該方法;

使用場景:已經獲得類對象實例的狀況;

示例代碼以下:

public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void goToSchool(){
        System.out.println("go to school");
    }
    public static void main(String[] args) throws Exception {
        //一、Class.forName("全類名")
        Class aClass = Class.forName("com.sean.Student");
        System.out.println(aClass);

        //二、類名.class
        Class bClass = Student.class;
        System.out.println(bClass);

        //三、類對象.getClass()
        Student student = new Student();
        Class cClass = student.getClass();
        System.out.println(cClass);
    }
}

PS:同一個字節碼文件(*.class),再一次程序運行中,只會被加載一次,三種方式獲取的Class類對象是同一個,能夠經過比較aClass,bClass和cClass來驗證;

Class對象的使用

下面咱們就簡單列出幾個經常使用的功能,其餘功能使用能夠參見JAVA的API文檔中的Class類。

這裏咱們建立一個Student類,便於下面咱們使用反射操做Student類對象。

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void goToSchool(){
        System.out.println("go to school");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

一、獲取成員變量對象(Filed),操做類的成員變量

方法 用途
getField(String name) 得到某個公有的屬性對象
getFields() 得到全部公有的屬性對象
getDeclaredField(String name) 得到某個屬性對象
getDeclaredFields() 得到全部屬性對象

Filed類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Filed對象獲取以及設置成員變量的值。

public static void main(String[] args) throws Exception {
        Class bClass = Student.class;
        //獲取Student對象的全部public屬性成員變量Filed對象
        Field[] fields = bClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //獲取Student對象中name屬性成員變量,由於name爲私有,這裏會拋java.lang.NoSuchFieldException異常
        Field name = bClass.getField("name");
        System.out.println(name);

        //獲取Student對象中name屬性成員變量Filed對象
        Field name1 = bClass.getDeclaredField("name");
        System.out.println(name1);
        /**
         * setAccessible(true)暴力反射
         * 這裏因爲name屬性是私有成員變量,不加這一句,
         * 後面的獲取以及設置成員變量會拋java.lang.IllegalAccessException異常
         */
        name1.setAccessible(true);

        //獲取name成員變量的值
        Student student = new Student();
        Object o = name1.get(student);
        System.out.println(o);

        //設置name成員變量的值
        name1.set(student,"zhangsan");
        System.out.println(student.getName());

   }

二、獲取構造方法對象(Constructor),操做類的構造函數

方法 用途
getConstructor(Class...<?> parameterTypes) 得到該類中與參數類型匹配的公有構造方法
getConstructors() 得到該類的全部公有構造方法
getDeclaredConstructor(Class...<?> parameterTypes) 得到該類中與參數類型匹配的構造方法
getDeclaredConstructors() 得到該類全部構造方法

Constructor類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Constructor對象建立Student對象。

public static void main(String[] args) throws Exception {

        Class bClass = Student.class;
        //獲取Student對象的無參構造函數Constructor對象
        Constructor constructor = bClass.getConstructor();

        //利用獲取到的Constructor對象建立Student對象
        Object o = constructor.newInstance();
        System.out.println(o);

}

三、獲取成員方法對象(Method),操做類的成員方法

方法 用途
getMethod(String name, Class...<?> parameterTypes) 得到該類某個公有的方法
getMethods() 得到該類全部公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes) 得到該類某個方法
getDeclaredMethods() 得到該類全部方法

Method類具體的用法能夠查看JAVA的API文檔,這裏咱們只演示了利用獲取到的Method對象執行執行Student類的成員方法。

public static void main(String[] args) throws Exception {

        Class bClass = Student.class;
        //獲取Student對象的goToSchool成員方法Method對象
        Method goToSchool = bClass.getMethod("goToSchool");

        //利用獲取到的Method對象執行Student類中的成員方法
        Student student = new Student();
        goToSchool.invoke(student);

}

四、獲取類名

方法 用途
getName() 得到該類的類名
public static void main(String[] args) throws Exception {

        Class bClass = Student.class;
        //獲取Student對象的類名
        String name = bClass.getName();
        System.out.println(name);
}

總結

JAVA中有不少開源的框架(框架是半成品的軟件,能夠在框架的基礎上進行編碼),使用這些框架能極大的簡化咱們的開發過程。而反射是框架的靈魂。固然不瞭解反射咱們也可使用這些框架進行開發,但瞭解反射的機制,能讓咱們知其然,知其因此然,在使用這些框架的時候更加駕輕就熟。

相關文章
相關標籤/搜索