框架必經之路:java反射知識點總結

反射庫(reflection library) 提供了一個非常豐富且精心設計的工具集, 以便編寫能夠動態操縱 Java 代碼的程序。這項功能被大量地應用於 JavaBeans 中,它是 Java 組件的體系結構。 - - - - - - - - - - - - - - - - - - -源於Java核心技術(卷Ⅰ)的引用

在理解反射之前需要了解類加載機制

一、什麼是反射

能夠分析類能力的程序稱爲反射(reflective)。

二、獲得class類對象的三種方式

在程序運行期間,Java 運行時系統始終爲所有的對象維護一個被稱爲運行時的類型標識。這個信息跟蹤着每個對象所屬的類。 虛擬機利用運行時類型信息選擇相應的方法執行。
然而,可以通過專門的 Java 類訪問這些信息。保存這些信息的類被稱爲 Class, 這個名字很容易讓人混淆。Object 類中的 getClass( ) 方法將會返回一個 Class 類型的實例。

  1. 類名.class(例如:Student.class)
  2. 對象.getClass()
Random generator = new Random():
Class cl = generator.getClass() ;
String name = cl.getName(); // name is set to "java.util.Random"
  1. 還可以調用靜態方法 forName 獲得類名對應的 Class 對象。
String className = "java.util.Random";
Class cl = Class.forName(className) ;

如果類名保存在字符串中, 並可在運行中改變, 就可以使用這個方法。當然, 這個方法只有在 dassName 是類名或接口名時才能夠執行。 否則,forName 方法將拋出一個 checkedexception ( 已檢查異常)。無論何時使用這個方法, 都應該提供一個異常處理器(exception handler) 。

String className = "java.util.Random";
Class cl = null;
try {
	cl = Class.forName(className);
} catch (ClassNotFoundException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}
		

三、通過反射來創建對象(生成類的實例)

//通過反射創建,需要注意此處是需要拋出異常的
Student student = Student.class.newInstance();

//通過new
Student student1 = new Student();

兩者創建對象是等價的,由此我們可以看出創建對象不一定非等通過new 來實現。

那麼我們就要想既然可以通過new來生成實例,爲什麼還需要反射呢?
解釋:我們知道通過new來創建對象比反射生成的實例要快,但是我們可能遇到過一種情況,new沒辦法使用的時候,比如說我們在使用框架的時候事先不知道這些類,沒辦法通過new來創建實例,只能通過反射來生成實例。我們是迫不得已的時候才使用反射來生成實例。
還有就是比如我們在使用tomcat開啓動web項目的時候,tomcat開發者不知道項目中會有什麼類,無法通過new來生成類的實例,所以tomcat容器寫了一個類的模板,運行的時候利用反射獲取類信息,然後生成對應的實例,然後執行調用方法。

附:簡易類加載機制圖
在這裏插入圖片描述

四、調用任意方法

在 C 和 C++ 中, 可以從函數指針執行任意函數。從表面上看, Java 沒有提供方法指針,即將一個方法的存儲地址傳給另外一個方法, 以便第二個方法能夠隨後調用它。事實上,Java 的設計者曾說過:方法指針是很危險的,並且常常會帶來隱患。 他們認爲 Java 提供的接口(interface) 是一種更好的解決方案。然而, 反射機制允許你調用任意方法

我們來看代碼:

1)、我先定義了一個學生類,注意age屬性是私有的

public class Student {
	private int age;

	@Override
	public String toString() {
		return "Student [age=" + age + "]";
	}
	
}

2)、

public class TestReflect {
	public static void main(String[] args) {
		Student student = new Student();
		
		try {
			Field age = Student.class.getDeclaredField("age");
			
			//設置可訪問非常重要
            age.setAccessible(true);
		
			age.set(student,20);
            System.out.println(student);
            System.out.println(age.get(student));
            
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println("------------------------------------------------");
		
		try {
			Method toString = Student.class.getDeclaredMethod("toString");
			Object invoke;
			invoke = toString.invoke(student);
			System.out.println(invoke);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

運行結果:
在這裏插入圖片描述

1、我們通過第一個try-catch可以看到即使是對象中的私有屬性通過反射也是可以訪問到的,前提是設置可訪問的屬性。
2、通過第二個try-catch的應用我們便實現了利用反射機制中的invoke方法來調用對象中的方法,也就是我們通常所說的代理,從這裏我們可以看到,反射和代理是在一起使用的。

五、反射的用途

說了這麼多,反射的用途到底是什麼,反射主要的作用是什麼?

通過以上的介紹我們可以總結兩句話:
1、通過反射獲取類信息;
2、根據類信息生成實例(實例化功能);
3、反射最終的目的是拿到類的實例。

拓展:

反射除了這些,在我們的Spring框架中的應用是很多很多的,比如說ioc和aop,springMVC原理等等都用到了反射機制,反射在框架中應用很廣,這是一個非常重要的知識點,對於我們學習web是必須要掌握的。

如果大家有興趣可以閱讀Java核心技術(卷Ⅰ)這本書,裏面有對反射機制更詳細的講解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章