Java 反射詳解,重要方法解析

概念

1.反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法。

2.反射可以在一個類運行的時候獲取類的信息的機制,可以獲取在編譯期不可能獲得的類的信息。

3.對於任意一個對象,都能調用它的任意一個方法和屬性。

4.因為類的信息是保存在Class對象中的,而這個Class對象是在程序運行時被類加載器(ClassLoader)動態加載的。

5.當類加載器裝載運行了類後,動態獲取Class對象的信息以及動態操作Class對象的屬性和方法的功能稱為Java語音的反射機制。

作用:

1.反編譯:.class —> .java。

2.通過反射機制訪問Java對象中的屬性、方法、構造方法等。

反射原理

Java反射的原理:java類的執行需要經歷以下過程,


Java 反射詳解,重要方法解析

類加載


編譯:.java文件編譯後生成.class字節碼文件

加載:類加載器負責根據一個類的全限定名來讀取此類的二進制字節流到JVM內部,並存儲在運行時內存區的方法區,然後將其轉換為一個與目標類型對應的java.lang.Class對象實例

連接:細分三步

驗證:格式(class文件規範) 語義(final類是否有子類) 操作

準備:靜態變量賦初值和內存空間,final修飾的內存空間直接賦原值,此處不是用戶指定的初值。

解析:符號引用轉化為直接引用,分配地址

初始化:有父類先初始化父類,然後初始化自己;將static修飾代碼執行一遍,如果是靜態變量,則用用戶指定值覆蓋原有初值;如果是代碼塊,則執行一遍操作。


Java的反射就是利用上面第二步加載到jvm中的.class文件來進行操作的。.class文件中包含java類的所有信息,當你不知道某個類具體信息時,可以使用反射獲取class,然後進行各種操作。


Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;並且能改變它的屬性。

總結說:反射就是把java類中的各種成分映射成一個個的Java對象,並且可以進行操作。

獲取class的三種方式


Java 反射詳解,重要方法解析

獲取類

Class類主要方法

getName():獲得類的完整名字。

getFields():獲得類的public類型的屬性。

getDeclaredFields():獲得類的所有屬性。包括private 聲明的和繼承類

getMethods():獲得類的public類型的方法。

getDeclaredMethods():獲得類的所有方法。包括private 聲明的和繼承類

getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name參數指定方法的名字,parameterTypes 參數指定方法的參數類型。

getConstructors():獲得類的public類型的構造方法。

getConstructor(Class[] parameterTypes):獲得類的特定構造方法,parameterTypes 參數指定構造方法的參數類型。

newInstance():通過類的構造方法創建這個類的一個對象。

代碼測試方法:

Person.java 類:


<code>package reflect;import java.util.Date;/** * * * @author pine */public class Person {    private String username;    private int age;    private Date birthDay;    public String nick;    public Person(String username){        this.username = username;    }    public Person(){    }    public Person(String username,int age){        this.username = username;        this.age = age;    }    public String getNick() {        return nick;    }    public void setNick(String nick) {        this.nick = nick;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Date getBirthDay() {        return birthDay;    }    public void setBirthDay(Date birthDay) {        this.birthDay = birthDay;    }    private void sayHello(){        System.out.println("person sayHello ---");    }    public void workIng(){        System.out.println("person work ing ---");    }    @Override    public String toString() {        return "Person{" +                "username='" + username + '\\'' +                ", age=" + age +                ", birthDay=" + birthDay +                ", nick='" + nick + '\\'' +                '}';    }}/<code>

ReflectTest.java類:

<code>package reflect;import com.alibaba.fastjson.JSON;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * * 反射 * @author anzy */public class ReflectTest {    public static void main(String[] args) {//       testClassEqual();        testMethodClass();    }    public static void testClassEqual(){        //1、對象調用 getClass() 方法來獲取,通常應用在:比如你傳過來一個 Object        //類型的對象,而我不知道你具體是什麼類,用這種方法        Person person = new Person();        Class c1 = person.getClass();        //2、通過類名.class 方式獲取,此方法最為安全可靠,性能高        //  這說明任何一個類都有一個隱含的靜態成員變量 class        Class c2 = Person.class;        //3、通過 Class 對象的 forName() 靜態方法來獲取,用的最多,        //   但可能拋出 ClassNotFoundException 異常        Class c3 = null;        try {            c3 = Class.forName("reflect.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.out.println(c1.equals(c2));        System.out.println(c1.equals(c3));        System.out.println(c3.equals(c2));    }    public static void testMethodClass(){        Class c3 = null;        try {            c3 = Class.forName("reflect.Person");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.out.println("c3.getName():" + c3.getName());        // 獲得類的public類型的屬性。        Field[] fields = c3.getFields();        System.out.println("c3.getFields():" + JSON.toJSON(fields));        //輸出結果:c3.getFields():[{"accessible":false,"declaredAnnotations":[],"synthetic":false,"annotatedType":        // {"declaredAnnotations":[],"annotations":[],"type":"java.lang.String"},        // "enumConstant":false,"name":"nick","annotations":[],"genericType":"java.lang.String",        // "modifiers":1,"type":"java.lang.String","declaringClass":"reflect.Person"}]        // 從輸出結果可以看到,只拿到了Person類中的nick public屬性。        Field[] fieldsAll = c3.getDeclaredFields();        System.out.println("c3.getDeclaredFields():" + JSON.toJSON(fieldsAll));        try {            // 只能獲取public方法,獲取private會報錯:java.lang.NoSuchMethodException: reflect.Person.sayHello()            Method method = c3.getMethod("workIng",null);            System.out.println("method: " + method);            Method[] methods = c3.getMethods();            System.out.println("methods: " + methods);            // public,private 方法都能獲取            Method declaredMethod = c3.getDeclaredMethod("sayHello",null);            System.out.println("declaredMethod: " + declaredMethod);            Method[] declaredMethods = c3.getDeclaredMethods();            System.out.println("declaredMethods: " + declaredMethods);            // 獲取構造函數            Constructor<person> constructors[] = c3.getConstructors();            System.out.println("constructors: " + constructors);            // JSON.toJSON(constructors) 會報錯,棧溢出 Exception in thread "main" java.lang.StackOverflowError//            System.out.println("constructors: " + JSON.toJSON(constructors));            // 通過類的構造方法創建這個類的一個對象。            Person person = constructors[0].newInstance("pine",1);            System.out.println("person: " + person);        } catch (NoSuchMethodException e) {            e.printStackTrace();        }catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }}/<person>/<code>


c3.getMethod()拿到的結果:


Java 反射詳解,重要方法解析

c3.getMethod()拿到的結果:

c3.getDeclaredMethods() 拿到的結果


Java 反射詳解,重要方法解析

c3.getDeclaredMethods() 拿到的結果

兩個對比可以發現:

getMethods() 能夠獲取Object類中的public方法。

getDeclaredMethods()獲取不到。

讓我們引發思考想到了,普通類與Object的關係:

Object類是一切java類的父類,對於普通的java類,即便不聲明,也是默認繼承了Object類。典型的,可以使用Object類中的toString()方法。

Class能實現的功能

1判斷對象屬於哪個類

Person person = new Person();

Class class2= person.getClass();

System.out.println("class2:"+class2);

輸出:class2:class reflect.Person

2獲取類信息

Class class1 = Person.class;

Method[] methods = class1.getMethods();

Method[] declaredMethods = class1.getDeclaredMethods();

Field[] declaredFields = class1.getDeclaredFields();


3構建對象

Person person = new Person();

Class class2= person.getClass();

Object o = class2.newInstance();

//強轉前先用instanceof判斷

if(o instanceof Person){

((Person) o).workIng();

}


4動態執行方法

Class class1 = Class.forName("reflect.Person");

Method work = class1.getDeclaredMethod("work");

Person person = new Person();

work.invoke(person);


5動態操作屬性

Class class1 = Class.forName("reflect.Person");

Person person = new Person();

Field field = class1.getDeclaredField("username");

field.set(person,"pine");

6動態代理


其他:

分享一下與內容有關的思維導圖與流程圖

反射思維導圖:https://www.processon.com/view/link/5e1eb718e4b0169fb52123db
類加載流程圖:https://www.processon.com/view/link/5e1eb5f6e4b04e6f9a263797


希望能對大家有幫助,有問題的地方希望大家指正。


分享到:


相關文章: