反射

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
相关文章
相关标签/搜索