Java-反射
1.反射介紹
1.1 什么是反射
Java 反射機制是 Java 語言一個很重要的特性,它使得 Java 具有了“動態(tài)性”。在 Java程序運行時,對于任意的一個類,我們能不能知道這個類有哪些屬性和方法呢?對于任意的一個對象,我們又能不能調(diào)用它任意的方法?答案是肯定的!這種動態(tài)獲取類的信息以及動態(tài)調(diào)用對象方法的功能就來自于 Java 語言的反射(Reflection)機制。
1.2 反射的作用
簡單來說兩個作用,RTTI(運行時類型識別)和 DC(動態(tài)創(chuàng)建)。我們知道反射機制允許程序在運行時取得任何一個已知名稱的 class 的內(nèi)部信息,包括其 modifiers(修飾符),fields(屬性),methods(方法)等,并可于運行時改變 fields 內(nèi)容或調(diào)用methods。那么我們便可以更靈活的編寫代碼,代碼可以在運行時裝配,無需在組件之間進行源代碼鏈接,降低代碼的耦合度;還有動態(tài)代理的實現(xiàn)等等;但是需要注意的是反射使用不當會造成很高的資源消耗!
Java 反射機制是 Java 語言一個很重要的特性,它使得 Java 具有了“動態(tài)性”。
反射機制的優(yōu)點:
反射機制的缺點:
2. 創(chuàng)建對象過程
2.1 創(chuàng)建 Java 對象的三個階段
2.2 創(chuàng)建對象時內(nèi)存結(jié)構(gòu)
實際上,我們在加載任何一個類時都會在方法區(qū)中建立“這個類對應(yīng)的 Class 對象”,由于“Class 對象”包含了這個類的整個結(jié)構(gòu)信息,所以我們可以通過這個“Class 對象”來操作這個類。
我們要使用一個類,首先要加載類;加載完類之后,在堆內(nèi)存中,就產(chǎn)生了一個 Class 類型的對象(一個類只有一個 Class 對象),這個對象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個對象知道類的結(jié)構(gòu)。這個對象就像一面鏡子,透過這個鏡子可以看到類的結(jié)構(gòu),所以,我們形象的稱之為:反射。 因此,“Class 對象”是反射機制的核心。
3. 反射的具體實現(xiàn)
3.1 獲取 Class 對象的三種方式
3.1.1 創(chuàng)建Users類
public class Users {private String username;private String userage;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getUserage() {return userage;}public void setUserage(String userage) {this.userage = userage;} }3.1.2 通過 getClass()方法獲取 Class 對象
public class Test {public static void main(String[] args) {Users users = new Users();Class cls = users.getClass();System.out.println(cls); //class com.Reflection.Users} }3.1.3 通過.class 靜態(tài)屬性獲取 Class 對象
public class Test {public static void main(String[] args) {Class cls = Users.class;System.out.println(cls); //class com.Reflection.Users} }3.1.4 通過 forName()獲取 Class 對象
public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);System.out.println(cls); //class com.Reflection.Users} }3.2 獲取類的構(gòu)造方法
3.2.1 修改Users類
public class Users {private String username;private String userage;public Users() {}public Users(String username, String userage) {this.username = username;this.userage = userage;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getUserage() {return userage;}public void setUserage(String userage) {this.userage = userage;} }3.2.2 獲取構(gòu)造方法
import java.lang.reflect.Constructor;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);//獲取無參構(gòu)造方法Constructor ctor1 = cls.getConstructor();//獲取有參構(gòu)造方法Constructor ctor2 = cls.getConstructor(String.class, String.class);System.out.println(ctor1); //public com.Reflection.Users()System.out.println(ctor2); //public com.Reflection.Users(java.lang.String,java.lang.String)} }3.2.3 通過構(gòu)造方法創(chuàng)建對象
import java.lang.reflect.Constructor;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);//獲取有參構(gòu)造方法Constructor ctor = cls.getConstructor(String.class, String.class);//實例化對象Users user = (Users) ctor.newInstance("小明", "18");System.out.println("姓名:" + user.getUsername() + "\t年齡:" + user.getUserage());//姓名:小明 年齡:18} }3.3 獲取類的成員變量
3.3.1 獲取成員變量
import java.lang.reflect.Field;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);Field field1 = cls.getDeclaredField("username");Field field2 = cls.getDeclaredField("userage");System.out.println(field1.getName()); //usernameSystem.out.println(field2.getName()); //userage} }3.3.2 操作成員變量
import java.lang.reflect.Field;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);Field field = cls.getDeclaredField("username");field.setAccessible(true); //將字段設(shè)置為可以訪問的//對象實例化Users user = (Users) cls.newInstance();//為成員變量賦值field.set(user, "朱小明");//獲取成員變量的值String str = (String) field.get(user);System.out.println(str);} }3.4 獲取類的方法
3.4.1 修改Users類
public class Users {private String username;private String userage;public Users() {}public Users(String username, String userage) {this.username = username;this.userage = userage;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getUserage() {return userage;}public void setUserage(String userage) {this.userage = userage;}public void HelloWorld() {System.out.println("Hello World");} }3.4.2 獲取方法并調(diào)用
import java.lang.reflect.Method;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);//根據(jù)方法名稱獲取方法Method method = cls.getDeclaredMethod("HelloWorld");//實例化對象Users user = (Users) cls.newInstance();//調(diào)用方法method.invoke(user); //Hello World} }4. setAccessible 方法
setAccessible()方法:
setAccessible 是啟用和禁用訪問安全檢查的開關(guān)。值為 true 則指示反射的對象在使用時應(yīng)該取消 Java 語言訪問檢查。值為 false 則指示反射的對象應(yīng)該實施 Java 語言訪問檢查;默認值為 false。
由于 JDK 的安全檢查耗時較多,所以通過 setAccessible(true)的方式關(guān)閉安全檢查就可以達到提升反射速度的目的。
import java.lang.reflect.Method;public class Test {public static void main(String[] args) throws Exception {String className = "com.Reflection.Users";Class cls = Class.forName(className);//根據(jù)方法名稱獲取方法Method method = cls.getDeclaredMethod("HelloWorld");//忽略安全檢查method.setAccessible(true);//實例化對象Users user = (Users) cls.newInstance();//調(diào)用方法method.invoke(user); //Hello World} }總結(jié)
- 上一篇: 公众号代运营与自运营相比,优势体现在哪些
- 下一篇: 深度学习入门笔记(四):向量化