Java反射機制是指在運行狀態中,對於任意一個類,都可以知道這個類全部的屬性和方法;對於任何一個對象,都可以調用它的任意一個方法和屬性。Java反射機制爲Java自己帶來了動態性。(反射提供了一種運行期獲取對象元信息的手段,經過反射,咱們能夠在運行時得到程序中每個類的成員和成員的信息)java
當咱們獲得一個class對象後,若是咱們不知道該class對象屬於哪一個類的class對象,咱們可也用以下方式判斷:數組
public native boolean isInstance(Object obj);
下面是一個使用例子,來判斷clazz是否是String類的class對象:測試
boolean flag=clazz.isInstance(new String ());
獲取到一個類的Class對象後,能夠獲取類的各類信息,進行不少操做。
如:code
建立實例
獲取方法信息
獲取構造器信息
獲取類的成員變量信息
利用反射建立數組
......對象
能夠查看Class類的源代碼,裏面的方法都是用來獲取一個類的詳細信息的。繼承
經過反射建立對象主要有兩種方式。
(1)使用Class對象的newInstance()方法來建立Class對象對應的實例。get
Class clazz=String.class; String str1=(String) clazz.newInstance();
這種方式是使用無參構造器來建立實例的。原型
(2)先經過Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來建立實例。it
Class clazz=String.class; Constructor constructor=clazz.getConstructor(String.class); constructor.newInstance("hello");
這種方式的好處是可使用指定的構造器來建立實例。io
獲取該類的public方法:
public Method[] getMethods() throws SecurityException
獲取該類的全部方法:
public Method[] getDeclaredMethods() throws SecurityException
獲取指定方法:
public Method getMethod(String name, Class<?>... parameterTypes)
該方法第一個參數是要獲取的方法名,後面一個可變數組是要獲取的方法的參數,能夠看到返回的是一個Method對象,經過它能夠獲得指定的方法的各類信息。
獲取一個類的指定方法信息後,就能夠用Method實例的invoke方法調用該指定方法。
invoke方法原型以下:
public Object invoke(Object obj, Object... args)
使用方式以下:
public class Hello { public int add(int a,int b){ return a+b; } public static void main(String[] args) throws Exception { Class clazz = Hello.class; Hello hello=(Hello)clazz.newInstance(); Method method = (Method) clazz.getMethod("add", int.class, int.class); Object result=method.invoke(hello,1,2); System.out.println(result); } }
以上就是使用反射的方式來執行一個方法。
在Java中,數組也是一種特殊的引用類型,它也能夠賦值給一個Object應用。利用反射建立數組主要用到Array
類。
下面咱們看一下利用反射建立數組的例子:
// 建立長度爲10的String類型的一維數組 Object array= Array.newInstance(String.class,10); String[] strArray=(String[]) array; // 向數組添加元素 Array.set(array,0,"Java"); Array.set(array,1,"C++"); Array.set(array,2,"PHP"); System.out.println(Arrays.asList(strArray));
輸出結果以下:
[Java, C++, PHP, null, null, null, null, null, null, null]
從JDK5之後,Java的Class類增長了泛型的功能,從而容許使用泛型來限制Class類。經過在反射中使用泛型,能夠避免使用反射生成的對象須要強制轉換。
Class類的定義以下:
public final class Class<T>
因此咱們經過某種方式得到一個類的Class對象後,不要忘記讓其帶上泛型信息。下面例子能夠簡單地說明:
Class cls1=new String().getClass(); String str1=(String)cls1.newInstance();
上面得到String類的class對象後,沒有帶上泛型信息,而後咱們用其建立實例時就須要強制類型轉換。咱們能夠加上泛型將以上狀況改善:
Class<? extends String> cls2=new String().getClass(); String str2=cls2.newInstance();
其中getClass和newInstance方法的原型以下。
Object類裏的getClass()方法:
public final native Class<?> getClass();
Class類的原型及其裏面的newInstance()方法:
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement { //省略代碼.... public T newInstance() throws InstantiationException, IllegalAccessException { //省略代碼..... } //省略代碼.... }
經過反射得到成員變量的Field對象後,就能夠很容易地得到改爲員變量的數據類型。以下:
首先,有一個用來測試的類:
class MyField{ public String str; public Map<String,Object> map; }
咱們來獲取成員變量str
的信息:
Class<MyField> cls=MyField.class; Field strField=cls.getField("str"); Class<?> clsF=strField.getType(); System.out.println(clsF);
輸出:
class java.lang.String
但這種方式只適用於不含泛型成員變量,對於含有泛型的成員變量會丟失成員變量的泛型信息,如:Map<String,Object> map
。
咱們能夠用另外一種方式獲取帶有泛型的成員變量的信息:
Type clsM=mapField.getGenericType();
而後將Type對象強制轉換成ParameterizedType
對象,它表明被參數化的類型,也就是增長了泛型限制的類型。
它提供了以下兩個方法:
getRawType()
:返回沒有泛型參數的原始類型。getActualTypeArguments()
:返回泛型參數的類型,是一個數組。Class<MyField> cls=MyField.class; Field mapField=cls.getField("map"); Type type=mapField.getGenericType(); ParameterizedType parameterizedType=(ParameterizedType)type; Type rType=parameterizedType.getRawType(); System.out.println("原始類型:"+rType); Type[] typeArguments=parameterizedType.getActualTypeArguments(); for(int i=0;i<typeArguments.length;i++){ System.out.println("第"+i+"個泛型參數是:"+typeArguments[i]); }
輸出結果以下:
原始類型:interface java.util.Map 第0個泛型參數是:class java.lang.String 第1個泛型參數是:class java.lang.Object