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