反射簡介
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能成為JAVA語言的反射機制。
在《Java編程思想》中有RTTI(Run-Time Type Identification),通過運行時類型信息程序能使用基類的指針或引用來檢查這些指針或引用所指對象的實際派生類型。不過RTTI的定義我是在百度百科上看到的,看了一下很多都是C++的內容,這與這本書的作者先前有C++的背景有關。不過在這里我并不想區分RTTI與我這想要學習的Java中的反射,在學習Java的過程中俺只認反射……
首先談談我對于反射的一些認知吧,反射對于** 客戶端程序員 **來說可能并沒有多大的發揮空間,而且因為反射的性能并不理想,在很多場景都是需要避免使用反射的。但是試想一下我現在要實現一個Json字符串映射到Java實體類的東西,這個時候就需要通過反射來拿到實體類的屬性信息了,之后再處理Json字符串,將對應的值賦給實體類對應的屬性。
在了解Java反射之前首先需要了解一個東西:Class
Class
類是程序的而一部分,每個類都有一個Class對象。在Java中,所有的類都是在對其第一次使用時,動態加載到JVM中的。因為Java的這個特性,曾經在網上看到過將Java理解為解釋型語言的,不過究竟該如何理解才好,可以給出一個大神的博客:R大,感興趣可以自行閱讀。
回到本文,當程序創建第一個對類的靜態成員的引用時,就會加載這個類。Java程序在它開始運行前并非完全被加載,其各個部分是在必需時才加載。
前面提到了每個類都有一個Class對象,這個類的所有對象都由其產生的Class對象產生。為了產生這個Class對象,JVM會使用類加載器將這個類加載到JVM中。
下面直接上code來說明一些問題。
public class TestClassType {
//構造函數
public TestClassType() {
System.out.println("構造函數");
}
//靜態的參數初始化
static {
System.out.println("靜態的參數初始化");
int i = 100;
System.out.println("i=" + i);
}
//非靜態的參數初始化
{
System.out.println("非靜態的參數初始化");
}
}
public class HelloWorld {
public static void main(String... args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class testTypeForName = Class.forName("TestClassType");
TestClassType t = (TestClassType) testTypeForName.newInstance();
}
}
當我使用Class.forName時這個類被載入內存,靜態代碼塊的代碼被執行,當我們使用Class對象創建一個該類的對象時,會先初始化非靜態的屬性和非靜態的代碼塊,之后調用構造器。在《Java編程思想》說構造器也是類的靜態方法,這我認為是作者的疏忽。關于這一塊的討論可以戳這里傳送門
繼續來補全,Class可以說是java反射的核心類,以上簡單的介紹了一下Class,以下繼續了解反射。
核心方法
成員屬性
getFields():獲得類的public類型的屬性
getDeclaredFields():獲得類的所有屬性
getField(String name)
getDeclaredField(String name)成員方法
getMethods():獲得類的public類型的方法
getDeclaredMethods():獲得類的所有方法
getMethod(String name, Class[] parameterTypes):獲得類的特定方法getDeclaredMethod(String name, Class[] parameterTypes):獲得類的特定方法構造方法:
getConstructors():獲得類的public類型的構造方法。
getDeclaredConstructors():獲得類的所有構造方法。
getConstructor(Class[] parameterTypes):獲得類的特定構造方法getDeclaredConstructor(Class[] params);獲得類的特定方法
下面簡單的使用其中的一些方法,首先是用來測試的類:
package reflect;
/**
* Created by luojun on 2017/1/9.
*/
public class Person {
public String name;
private int age;
public String getaName() {
return name;
}
public int getAge() {
return age;
}
private void setAge(int age){
this.age = age;
}
public Person(String name,int age) {
this.name = name;
this.age = age;
System.out.println("共有構造方法被調用");
}
private Person(){
System.out.println("私有構造方法被調用");
}
}
main:
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by luojun on 2017/1/9.
* desc
*/
public class Test {
public static void main(String... args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Person> personClz = Person.class;
Constructor<Person> cons = personClz.getDeclaredConstructor();
cons.setAccessible(true);
Person person = cons.newInstance();
Method m1 = personClz.getDeclaredMethod("setAge", int.class);
System.out.println("使用反射獲取到的方法名:" + m1.getName());
m1.setAccessible(true);
Method setAge = personClz
.getDeclaredMethod("setAge", int.class);
setAge.setAccessible(true);
setAge.invoke(person, 16);
System.out.println("使用反射初始化年齡之后年齡的值:" + person.getAge());
}
}
輸出:
由于自己現在并非些工具之人,所以對于反射的需求也不是很大,暫時就了解到這。