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

概念

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

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

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

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

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

作用:

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

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

反射原理

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


類加載


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

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

連接:細分三步

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

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

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

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


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


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

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

獲取class的三種方式


獲取類

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()拿到的結果:


c3.getMethod()拿到的結果:

c3.getDeclaredMethods() 拿到的結果


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


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