一、概念:
所谓反射,就是在程序运行期间,动态的获取类的属性,其中包括,属性(Field)、方法(Method)、构造器(constructor)。
1.1既然我提到了类,那我们先来看一看什么是类(或者说我们怎么能得到一个类对象)
package relfect;
public class WhatIsClass {
//这就是一个类(你new出来的,好像是废话),那么我们怎么获取这个类的Class对象呢?
Class clz;
void howTogetClass() throws ClassNotFoundException{
//方式一
clz=WhatIsClass.class.getClass();//这种方式在编译时获取的Class对象
//方式二 这个方式需要抛出一个ClassNotFound的异常
clz=Class.forName(“relfect.WhatIsClass”);//这种方式是在运行时获取的Class对象,由于参数为字符串,避免出错建议在properties文件中读取
}
}
1.2使用Class对象创建类的实例(与Constructor的运用)
WhatIsClass wic=(WhatIsClass) clz.newInstance();//获取WhatIsClass的实例
//这里需要注意的是,为保证newInstance()方法的正确调用,你的类对象中必须有默认的无参构造(public修饰)
1.2.1对于没有默认构造器的Class对象,创建实例的方法(这里用到的泛型有空会讲解)
对于使用构造器创建对象大家应该不陌生吧!
Constructor constructor=clz.getConstructor();//只能获取public访问级别的无参构造
constructor.setAccessible(true);//这个属性可以或略访问级别
Constructor<WhatIsClass> constructor=clz.getDeclaredConstructor();//可以或略访问级别来获取类对象的无参构造
WhatIsClass wic=constructor.newInstance();
1.2.3 如果构造器有参数呢?
比如
WhatIsClass 我们还沿用这个类,修改一下构造函数
private WhatIsClass (String arg1,String arg2,int arg3){};
那么对于这样的Class我们如何去创建实例呢?
Constructor constructor=clz.getConstructor(String.class,String.class,Integer.class);
constructor.setAccessible(true);//这个属性可以或略访问级别
Constructor constructor=clz.getDeclaredConstructor(String.class,String.class,Integer.class);//可以或略访问级别来获取类对象的无参构造
WhatIsClass wic=constructor.newInstance();
1.3 Field类中的属性
1.3.1 如何获取类中的属性
Field field=clz.getField(“username”);//假设我们要获取类中的一个username属性
field.setAccessible(true);//忽略属性的访问级别
String username=field.getName();
//我们也可以这样
Field[] fields = clz.getDeclaredFields();//忽略访问级别,获取所有对象组成的数组
String [] fieldName=new String[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldName[i]=fields[i].getName();
}
1.3.2 既然我们已经获得了属性,那么我们是不是也能获得与之对应的get和set方法呢!
Field field=clz.getField(“username”);//假设我们要获取类中的一个username属性
field.setAccessible(true);//忽略属性的访问级别
String username=field.getName();
PropertyDescriptor pd=new PropertyDescriptor(username, clz);
Method setUsername=pd.getWriteMethod();
setUsername.invoke(wic, "Hello World");
//我们也可以这样
Field[] fields = clz.getDeclaredFields();//忽略访问级别,获取所有对象组成的数组
String [] fieldName=new String[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldName[i]=fields[i].getName();
pd=new PropertyDescriptor(fieldName[i], clz);
Method writeSomeThing = pd.getReadMethod();//获得读方法
writeSomeThing.invoke(wic, fieldName[i]);
}
—当然我也也可以使用BeanInfo
BeanInfo beanInfo = Introspector.getBeanInfo(clz);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
//剩下的代码同上
补充:由于反射的大部分方法都是见名知意的,就不一一列举了,
对于RTTI,大部分人知道的是instanceOf(); //判断导某某类的是否是某某类的导出类
但对于反射来说只能调用clz.isInstance();//来进行//这个方法并不存在基类的概念
这是我的第一篇博客,后续想到什么,有空就会去写,觉得我的文章对你撸码有帮助的,就请继续关注
要是那里说的不对,也请指出。