反射
概念:將類的各個組成部分封裝爲其他對象,這就是反射機制。
好處:
1、可以在程序運行過程中,操作這些對象。
2、可以解耦,提高程序的可擴展性。
獲取Class對象的方式:
1、Class.forName(“全類名”):將字節碼文件加載進內存,返回Class對象
//多用於配置文件,將類名定義在配置文件中,讀取文件,加載類
2、類名.class:通過類名的屬性class獲取
//多用於參數的傳遞
3、對象.getClass( ):getClass( )方法在Object類中定義者。
//多用於對象的獲取字節碼的方式
結論:同一個字節碼文件(*.class)在一次程序運行中,只會被加載一次,無論通過哪一種方式獲取的Class對象都是同一個。
例子:Java反射獲取私有屬性並修改
關鍵步驟:setAccessible(true)
1、新建一個類,並設置私有屬性值
public class Student {
private String name = "kobe";
public String getName() {
return name;
}
}
2、新建測試類
import java.lang.reflect.Field;
public class TestSetAccessible {
public static void main(String[] args) throws Exception{
Student stu = new Student();
Class<?> clazz = Student.class;
// 獲得指定類的屬性
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
// 更改私有屬性的值
field.set(stu, "bryant");
System.out.println(stu.getName());
}
}
輸出結果:
bryant
反射的用途
-
反射最重要的用途就是開發各種通用框架,比如在spring中,我們將所有的類Bean交給spring容器管理,無論是XML配置Bean還是註解配置,當我們從容器中獲取Bean來依賴注入時,容器會讀取配置,而配置中給的就是類的信息,spring根據這些信息,需要創建那些Bean,spring就動態的創建這些類。還有在struts2的struts.xml中配置action,也是通過反射調用action。
-
還有在我們創建數據庫鏈接時,這句代碼
Class tc = Class.forName(“com.java.dbtest.TestConnection”)
就是告訴JVM去加載這個類,而加載的過程是在程序執行過程中動態加載的。通過類的全類名讓jvm在服務器中找到並加載這個類,而如果是使用別的數據庫,那就要換一個類了,如果是傳統寫死的方法創建,就要修改原來類的代碼,而對於反射,則只是傳入的參數就變成另一個了而已,可以通過修改配置文件,而不是直接修改代碼。 -
再比如我們有兩個程序員,一個程序員在寫程序的時候,需要使用第二個程序員所寫的類,但第二個程序員並沒完成他所寫的類。那麼第一個程序員的代碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機制,就可以讓第一個程序員在沒有得到第二個程序員所寫的類的時候,來完成自身代碼的編譯。只是如果這個類還沒有,獲取時會獲取不到,但不會導致編譯錯誤,更不會導致程序的崩潰。
-
還有當我們在使用 IDE(如 Eclipse\IDEA)時,當我們輸入一個隊長或者類並向調用它的屬性和方法時,一按 (“.”)點號,編譯器就會自動列出她的屬性或方法,這裏就會用到反射。