反射

Java反射機制是指在運行狀態中,對於任意一個類,都可以知道這個類全部的屬性和方法;對於任何一個對象,都可以調用它的任意一個方法和屬性。Java反射機制爲Java自己帶來了動態性。(反射提供了一種運行期獲取對象元信息的手段,經過反射,咱們能夠在運行時得到程序中每個類的成員和成員的信息)java

獲取Class對象

  • 使用Class類的forName靜態方方法。
  • 直接根據該類獲取(.class)。
  • 調用該類對象的getClass方法,該方法繼承自Object對象。

當咱們獲得一個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]

反射與泛型

泛型化的Class

從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
相關文章
相關標籤/搜索