分类: Java
2012-09-30 10:24:57
反射小结
转载自http://blog.csdn.net/xjwangliang/article/details/6553189
反射机制提供的功能很多,比如:
1、运行时判断对象所属的类
2、运行时创建一个类的对象
3、运行时得到类多具有的方法和属性
4、运行时改变属性和执行方法
1.每一种类型的对象和类对应同一个Class对象。
(1)得到对象的Class对象:对象.getClass()。
(2)得到类的Class对象:类.class.
以上两种还是有些区别,比如:
Class
对象getClass()返回Class extends 对象的类名>
Class
Class extends String> cl3 = "String".getClass();
另外泛型类型,编译之后去掉了泛型信息。
2.Java中每一种类型都有对应的Class对象,对于八种基本类型int、short、byte、long、float
double、boolean、char,获得其对应的Class对象
xxx.class
也可以使用对应的包装类型获得(例如int的包装类型为Integer)
XXX.TYPE
另外,对于void这个特殊的类型,它也有Class
void.class,相应的也可以Void.TYPE,其中Void是类。
以上的9种Class类型是基本类型,也就是说isPrimitive(xxx)返回true
3.得到对象的Class之后,我们可以得到对象的构造方法,方法,字段,包,对应于:
3.1【Constructor】代表构造方法。.
public Constructor
获得特定的public构造方法.。
public Constructor>[] getConstructors()
获得public构造方法。
【注意】:上面的两个方法都是获得public的构造方法,但是有个特例,对于类中隐含的默认构造方法(不是自定义的无参构造方法),虽然它是public,却不能使用上面的方法,必须显示定义public的构造方法,或者使用下面的方法。
public Constructor
获得所有级别的特定构造方法
public Constructor>[] getDeclaredConstructors()
获得所有级别的构造方法
【注意】:可变参数是JDK1.5的新特性,以前使用数组表示
public Constructor
public Constructor
可变参数可以接收数组,但是反之不行
得到Constructor之后,可以通过Constructor可以获得实例对象:
public T newInstance(Object... initargs)
JDK1.5以前为public T newInstance(Object[] initargs)
【注意】:对于private的构造方法,要获得实例对象,必须先要Constructor对象.setAccessiable(true)。
【例子】:
不使用泛型
Constructor c = String.class.getDeclaredConstructor(StringBuffer.class);
String s = (String) c.newInstance(new StringBuffer("wangliang"));//需要转型
System.out.println(s);
使用泛型
Constructor
String s1 = c1.newInstance(new StringBuffer("wangliang1"));//对于泛型就不需要转型
System.out.println(s1);
Class也有个public T newInstance(),它是调用Constructor的public T newInstance()
创建此 Class对象所表示的类的一个新实例。使用默认无参构造。如果该类尚未初始化,则初始化这个类。而且此newInstance()方法不必显示定义public的构造方法,类中有隐含的默认构造方法。
同一个Class或者Constructor的调用两次newInstance()方法得到的是不同的对象
由无参构造方法获得对象:
Class对象.getConstrutor(new Class[]{}|null|空).newInstance(new Object[]{}|null|空)不一定要对应
3.2【Field】代表属性。
与构造方法类似,Field也有类似的方法:
public Field getField(String name)
public Field[] getFields()
以上只针对public级别,下面的方法可以访问任意级别:
public Field getDeclaredField(String name)
public Field[] getDeclaredFields()
【获得属性的值】
以上方法只是获得原对象的属性对应的对象,要获得属性的值
Field对象.get(null)获得静态属性的值
Field对象.get(原对象)获得(也可以是静态)属性的值
【设置属性的值】
Field对象.set(null)设置静态属性的值
Field对象.set(原对象,Object参数)设置(也可以是静态)属性的值
【注意】:对于private的Field,要获得和设置值,先要Field对象.setAccessiable(true)。另外对于final(非static)的Filed对象,设置值,即调用set()方法,必须Field对象.setAccessiable(true)。
【注意】:
1、对于static final的属性(声明时就初始化了),set()方法出错,无法改变。
2、对于static属性可以改变。
3、对于final的属性调用set()方法,都先要setAccessible(true),这与属性的访问级别不是一回事(即使是public也要设置)。
4、对于一般非static的final属性,如果是声明时就初始化了,也无法改变属性的值(但不会报错),只有在构造方法中初始化的才可以改变。
3.3【Method】代表方法。
与前面类似:
public Method getMethod(String name,Class>... parameterTypes)
public Method[] getMethods()
以上只针对public级别,下面的方法可以访问任意级别
public Method getDeclaredMethod(String name,Class>... parameterTypes)
public Method[] getDeclaredMethods()
【执行方法】获得了Medthod对象之后,可以执行方法:
Method对象.invoke(null, Object参数列表);null表示静态方法
Method对象.invoke(原对象,Object参数列表);执行方法
【注意】:对于private的Method,要获得和设置值,先要Method对象.setAccessiable(true)。如果方法没有参数,参数列表可为空或者null或者空的Object数组(new Object[]{})。
如果参数为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。如果参数为数组,Object参数列表就是new Object[]{new 类型[]{元素列表}}。
获得属性和方法所代表的对象都可以直接通过class得到,而不必通过对象;但是要得到属性的值(除了静态属性)以及执行方法(除了静态方法),都要通过对象。
3.4【Array】
Array允许对数组进行动态操作
判断Class是否为数组:isArray(),从而就知道了相应的对象是否为数组。但是能否打印一般类型的数组呢?
参数是一般的对象,obj.length,obj[i],obj[i].getClass()这些方法都不存在,因为obj是Object的对象,无这些方法和属性。也没法强制转换,因为不知道类型数组元素的类型(obj.getClass()得到的是数组的类型,而不是元素的类型;obj[i].getClass()是可以得到元素类型),就算知道,也要做多次判定。但是我们可以:
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);
for(int i=0;i
System.out.println(Array.get(obj, i));
//对应的set():static void set(Object array, int index, Object value)
}
}else{
System.out.println(obj);
}
}