本文按照以下思路帮助自己和路人理清反射。
1.什么是反射?
2.反射能干什么?
3.怎么用?
4.案例实操:
5.总结:
一、什么是反射?
百度百科:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及
动态调用对象方法的功能称为java语言的反射机制。
说的通俗一点,反射是在程序编译完成后,在.class运行阶段起作用的,你给我传过来什么,我都能访问它祖宗十八代,从而达到我的目的。重点在于动态,动态指的是运行阶段,而非编译阶段。
二、反射能干什么?
常见的有加载数据库驱动中Class.forName(driverClass),还有许多框架例如spring也大量的使用反射,还有自己的项目中抽取dao层公共方法写到BaseDaoImpl中需要知道传递的实体类型等等,都可以通过反射来获取。
三、怎么用?
三种方式可以选择,总之是要获取Class类对象
3.1.通过对象(不常用,对象都有了还反过用对象再反射属性方法,多此一举)
Person p = new Person();
Class<? extends Person> clazz = p.getClass();
3.2.通过类名(不常用,没有必要)
Class<? extends Person> clazz = Person.class();
3.3.通过字符串全类名(常用,一般情况下,我们没法传递过去一个类对象,但是我们可以通过该类的全限定名,间接得到类的信息)
Class<?> clazz = Class.forName("com.xx.myReflect");
四、案例实操
前面都很简单,下面就使用第三种方式,具体测试反射在字段,普通方法,构造方法上的一些使用,其余的类似,自己探索,被测试的类如下。
4.1 测试字段
@Test
public void testField(){
try {
//通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类
Class<?> clazz = Class.forName("com.cissst.vo.MyReflect");
//因为要给字段中设值,因此产生Reflect的实例,父类是Object
Object object = clazz.newInstance();
//得到本类(不包含父类)中的声明字段数组
Field[] fields = clazz.getDeclaredFields();
//循环设置字段值,输出字段值
for(Field f : fields){
//因为某些字段或者方法是私有的,反射需要将此标识设置为true
f.setAccessible(true);
//判断如果当前字段类型是否是Integer
//如果使用getName,获取的是全限定名
if(f.getType().getSimpleName().equals("Integer")){
//是设置为1
f.set(object, 1);
}
//判断如果当前字段类型是否是String
if(f.getType().getSimpleName().equals("String")){
//是设置为..
f.set(object, "秦琼");
}
//最后输出,腰肢具体详情请查看API
System.out.println(f.get(object));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
4.2 测试方法
/*
* 测试普通方法
*/
@Test
public void testMethod(){
try {
//通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类
Class<?> clazz = Class.forName("com.cissst.vo.MyReflect");
//产生Reflect的实例,父类是Object
Object object = clazz.newInstance();
//指定方法名,指定参数类型,得到该方法,还有方法查API,很好用
Method method = clazz.getMethod("method", String.class);
//执行此方法
method.invoke(object, "李逵");
} catch (Exception e) {
e.printStackTrace();
}
}
4.3 测试构造方法
/*
* 测试构造方法
*
*/
@Test
public void testConstractorMethod(){
try {
//通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类
Class<?> clazz = Class.forName("com.cissst.vo.MyReflect");
//调用无参构造
Constructor<?> constructor = clazz.getDeclaredConstructor();
//通过无参构造实例化得到类对象
Object obj1 = constructor.newInstance();
//看得到的ojb和MyReflect是否是同一宗亲
System.out.println(obj1 instanceof MyReflect);
//得到所有的构造
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
//循环操作构造
for(Constructor<?> con : constructors){
//这里做个简单的判断,实际可能比这更复杂
if(con.getParameterCount()==0){
//无参构造实例化
Object ojb2 = con.newInstance();
//有参构造
}else if(con.getParameterCount()==2){
//有参构造实例化
Object ojb3 = con.newInstance(1,"林彪");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
被测试类:
package com.cissst.vo;
/**
* 普通类:用此类测试反射
* @author phoebe
*/
public class MyReflect{
//字段
private Integer id;
private String name;
/*
* 无参构造方法
*/
public MyReflect(){
System.out.println("无参构造is running");
}
/*
* 有参构造方法
*/
public MyReflect(Integer id,String name){
this.id = id;
this.name = name;
System.out.println("有参构造");
}
/*
* 无参普通方法
*/
public void method(){
System.out.println("无参普通方法");
}
/*
* 无参普通方法
*/
public void method(String str){
System.out.println("有参普通方法");
}
}
五、总结
反射使得代码更灵活,可以提高复用性。