主要用兩種形式:java
爲何不用RTTI,由於它有一個限制:類型必須是在編譯期間已知的。web
Java反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法。對於一個對象,都可以調用它的任意方法和屬性。api
這種動態獲取信息以及動態調用對象的方法的功能稱爲Java語言的反射機制。svg
要想使用反射機制,就必需要先獲取該類的字節碼文件對象(.class),經過字節碼文件對象,就可以經過該類中的方法獲取到咱們想要的全部信息(方法、屬性、類名、父類、實現的全部接口等等)。spa
在運行期,一旦咱們想生成那個類的一個對象,用於執行程序的JVM首先會檢查那個類型的class對象是否已經載入。若還沒有載入,JVM就會查找同名的.class文件,並將其載入。code
每個類對應着一個字節碼文件也就對應着一個class類型的對象,也就是字節碼文件對象。xml
在反射中,要獲取一個類或調用一個類的方法,咱們首先須要獲取到該類的class對象。對象
首先咱們介紹一下動態加載和靜態加載。繼承
動態加載:程序在運行時調用相應方法,即便其餘方法是錯誤的,程序依舊會執行。經過動態加載可讓程序的可延長性大大提高,對之後的維護和擴展有重要意義。接口
靜態加載:程序在編譯時執行。在執行過程當中加載全部可能執行到的程序。在這種加載方式下,只要加載中一個方法出錯,程序就不能運行。咱們通常寫程序默認的是靜態加載。
有三種方法:
Class.forName(類名)
Class clz = String.class
只適合在編譯前就知道要操做的Class。 obj.getClass()。
第一種有更好的擴展性,因此通常狀況下,第一種用的較多。
有兩種方式:
經過Class對象的newInstance()
方法
Class clz = Person.class;Person per = (Person)clz.newInstance();
經過Constructor對象的newInstance()
Class clz = Person.class; Constructor constructor = clz.getConstructor(); Person per = (Person)constructor.newInstance();
Class clz = Person.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Person per = (Person)constructor.newInstance("小明", 15);
經過class對象的getFields()
能夠獲取到class的非私有屬性。
經過class對象的getDeclaredFields()
方法能夠獲取包括私有屬性在內的全部屬性。
經過class對象得getMethods
獲取該類中的全部方法,包括繼承和實現的方法。
經過class對象得getDeclaredMethods
獲取該類中的全部方法(包括私有方法),不包括包括繼承方法。
PS:私有方法和私有屬性不能直接訪問,由於權限不夠。不過仍是有辦法的。
method.setAccessible(true)
field.setAccessible(true)
經過反射,咱們能夠調用其它類的私有方法。
import java.lang.reflect.Method;
class A
{
private void pow(int n)
{
System.out.println(n * n);
}
}
class Test
{
public static void main(String args[]) throws Exception
{
Class<A> c = A.class;
Object obj = c.newInstance();
Method m = c.getDeclaredMethod("pow", new Class[]{ int.class });
m.setAccessible(true);//修改訪問權限
m.invoke(obj, 4);//調用方法
}
}