反射
一、概述
1.定义:反射就是将java的各种成分映射成为相应的类,对映射的类可以进行相应的操作。
2.反射的基石:
Class:java程序中的各个类属于同一个事物,这个事物的名称就是Class
理解:众多的人可以用Person表示,那么众多的java类可以用Class表示
3.如何得到Class的实例对象:
1.类名.class
2.对象.getclass()
3.Class.forName(String)
注意:
1.int.class==Integer.Type boolean.class==Boolean.Type……只要在源程序中出现的类型,都有对应的Class实例对象(即对应的字节码文件,如void.class,int[].class)
2.同一类在内存中只有一个字节码文件对象(.class文件)
二、Class的成员的反射
1.构造方法的反射:
Class类中:
T newInstance() 创建空参数的新实例
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此所表示的类的指定公共构造方法
Constructor<?>[] getConstructors()
返回一个包含类的所有公共构造方法
Constructor getDeclaredConstructor(Class<>parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法
String getName() 以字符串形式返回此字节码的名称
Class<?>[] getInterfaces() 返回该类所实现接口的数组
Constructor类中:
T newInstance(Object... initargs)
使用此 Constructor 对象创建该构造方法新实例,并用指定的初始化参数初始化该实例
Class<?>[] getParameterTypes()
按照声明顺序返回 Class 对象的数组,这些对象描述了此 Class对象所表示的方法的形参类型
String getName() 以字符串形式返回此Class对象所表示实体的名称
2.对成员变量的反射:
public int x,private int y;
Class c = pt1.getClass();
Field fieldX = c.getField("x");
Object object = fieldX.get(pt1);
对私有成员(或者default)的暴力反射
Field f = c.getDeclaredField("y");
f.setAccessible(true);
Object object = f.get(pt1);
通过反射修改成员变量的值:
成员变量必须是public的
Field[] fields = obj.getClass().getFields();
for(Field field:fields) {
if(field.getType() == String.class){
String oldValue =(String)field.get(obj);
String newValue = oldValue.replace('d', 'a');
field.set(obj, newValue);
}
如果是private,或者default:
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field:fields) {
if(field.getType() == String.class){
field.setAccessible(true);
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('d', 'a');
field.set(obj, newValue);
}
3.对成员方法的反射:
String str = "avc";
Class c = Class.forName("java.lang.String");
//获取到要操作的方法
Method method = c.getMethod("charAt", int.class);
//方法的调用,如果方法时静态的method.invoke(null, 22)
System.out.println(method.invoke(str, 2));
4.对某个类的main方法的反射:
//运行时传递一个类名的参数arg[0]
String name = args[0];
Class c1 = Class.forName(name);
Method mainmethod = c1.getMethod("main", String[].class);
mainmethod.invoke(null, new String[]{"111","222"});
//会报异常,原因是参数个数不对(编译器会按照jdk1.4的语法将数组拆分成若干个参数,调用main就出错了)
//解决办法: mainmethod.invoke(Object obj, Object ...args);
1.mainmethod.invoke(null, (Object)new String[]{"111","222"});
2.mainmethod.invoke(null, new Object[]{new String[]{"111","222"}});
//这里编译器会做特殊处理,不会把参数当做数组看待,也就不会分散成若干个参数。
5.对数组的反射:
1.具有相同的维数和类型的数组,是同一种字节码
private static void printArry(Object obj) {
Class c = obj.getClass();
if(c.isArray()) {
int length = Array.getLength(obj);
for(int i=0;i<length;i++) {
System.out.println(Array.get(obj, i));
}
}else {
System.out.println(obj);
2.ArrayLsit.asList(Object[] obj)
如果传递int[],打印的是(类名@hashcode),因为int[]不是一个Object[],javac会按照jdk1.5将int[]数组搞成一个对象
如果传递String[],打印的是数组里面的内容,因为Stirng[]是Object[]数组,jdk要兼容低版本的javac,会走jdk1.4.
注意:通过反射无法获得数组的类型,只能获得数组里面的对象的类型
内省
一、概述
内省(Introspector):是一种特殊的java类,主要用于传递属性信息,这种java类中的方法主要用于访问私有的字段,并且符合某种规则命名。
如果一个类符合这种特点,我们可以称这个类为javaBean,我们可以按照普通的类来操作,也可把它作为一个javabean处理。
二、操作
1、PropertyDescriptor类(java.beans):PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
构造函数:
PropertyDescriptor(String propertyName, Class<> beanClass)
通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个 PropertyDescriptor
常用方法:
Method getReadMethod() 获得应该用于读取属性值的方法
Method getWriteMethod() 获得应该用于写入属性值的方法
2.简单操作
public static void main(String[] args) throws Exception {
ReflectPoint rp1 = new ReflectPoint("chenhong", 23);
String propertyName = "name";
String propertyName1 = "age";
Object object = getProperties(rp1, propertyName);
System.out.println(object);
Object object1 = getProperties(rp1, propertyName1);
System.out.println(object1);
String value = "chenxi";
Object value1 = new Integer(30);
setProperties(rp1, propertyName1, value);
}
//修改属性的值
private static void setProperties(Object rp1, String propertyName1,Object value) throws Exception{
//构造属性描述器PropertyDescriptor对象
PropertyDescriptor pd1 = new PropertyDescriptor(propertyName1, rp1.getClass());
//获取"写"方法
Method method = pd1.getWriteMethod();
//调用"写"方法,指定相应的值
method.invoke(rp1, value);
}
//获取属性的值
private static Object getProperties(Object rp1, String propertyName) throws Exception {
//构造属性描述器PropertyDescriptor对象
PropertyDescriptor= new PropertyDescriptor(propertyName, rp1.getClass());
//获取"读"方法
Method method = pd.getReadMethod();
//调用方法,获取其值
return method.invoke(rp1, null);
}
4、beanutils工具包操作JavaBean
1.导入BeanUtils工具包:加入jar包到工程中,引入commons-logging包的支持
2.方法:
BeanUtils.getProperties()
BeanUtils.setProperties()//对属性都是进行字符串操作
PropertyUtils.getProperties()//对属性本身类型进行操作
PropertyUtils.setProperties()