1、反射是什么?
2、反射对象
3、反射方法
4、反射在平时的应用
-----------------------------------------------反射是什么?----------------------------------------------------
1、反射是什么?
Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis中都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理模式等设计模式,同时也可以解决Java泛型擦除等令人苦恼的问题。本文我们就从实际应用的角度出发,来应用一下Java的反射机制。
通俗的讲:知道类全名和构造方法,我们可以通过反射得到一个对象。获得一个对象并知道他的方法,我们可以通过方法名执行该方法。适用于批量的重复工作的简化工作。
-----------------------------------------------反射对象----------------------------------------------------
2、反射对象
github源码地址
一个对象的初始化,就是对构造函数的初始化,那么构造函数有的没有参数,有的没有参数。那我们怎么用反射进行初始化呢?下面我们先看一个对没有参数的构造方法进行初始化的形式,代码如下:
准备工作,首先我们做一个Bean 来作为初始化的对象:
package com.tt.reflect;
public class TestBean {
private String status = "锁定";
private String name;
private String age;
public TestBean() {
}
public TestBean(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "TestBean [name=" + name + ", age=" + age + "]";
}
}
bean做好之后我们接下来对bean进行一下初始化,(无参初始化)
public TestBean getBean() {
TestBean testBean =null;
try {
testBean = (TestBean) Class.forName("com.tt.reflect.TestBean").newInstance();
} catch (InstantiationException e) {
//该对象不能实例化
e.printStackTrace();
} catch (IllegalAccessException e) {
//调用该类的构造方法,是Private访问权限。
e.printStackTrace();
} catch (ClassNotFoundException e) {
//没有找到对应的类
e.printStackTrace();
}
return testBean;
}
可以做一个简单的测试,看看这段代码是否可以进行TestBean的一个初始化。
那么接下来我们再写一个使用有参数的构造方法,来传参进行对象初始化,代码如下:
public TestBean getParamBean() {
TestBean testBean = null;
try {
testBean = (TestBean) Class.forName("com.tt.reflect.TestBean").getConstructor(String.class).newInstance("不锁定");
} catch (InstantiationException e) {
//该对象不能实例化
e.printStackTrace();
} catch (IllegalAccessException e) {
//调用该类的构造方法,是Private访问权限。
e.printStackTrace();
} catch (IllegalArgumentException e) {
//数据异常的错误
e.printStackTrace();
} catch (InvocationTargetException e) {
//反射异常
e.printStackTrace();
} catch (NoSuchMethodException e) {
//此方法不存在异常
e.printStackTrace();
} catch (SecurityException e) {
//权限不足
e.printStackTrace();
} catch (ClassNotFoundException e) {
//没有找到类
e.printStackTrace();
}
return testBean;
}
如上可以看到,我们分别对无参构造方法和有参构造方法进行了初始化。
那么我怎么怎么来验证他们之间的区别呢?
我们写一个测试的MainTest类来测试一下:
package com.tt.reflect;
public class MainTest {
public static void main(String[] args) {
ReflectTest r = new ReflectTest();
//注意点,如果bean里面有其他的构造函数,则需要自己写明 无参构造函数否在会报错
TestBean bean = r.getBean();
System.out.println("bean:"+bean.getStatus());
TestBean paramBean = r.getParamBean();
System.out.println("paramBean:"+paramBean.getStatus());
}
}
通过以上两种方式初始化测试结果如下:
bean:锁定
paramBean:不锁定
第一个没有参数,没有改变status属性,第二个传入参数为不锁定,实现了传参初始化。
-----------------------------------------------反射方法----------------------------------------------------
3、反射方法
/**
* 反射方法
* @return
*/
public Object reflectMethod() {
Object obj = null;
//获取一个bean
TestBean bean = getBean();
try {
//有参方法 一个方法可以有多个参数 根据参数的循序指定 参数的类型即可 逗号分隔
Method method = bean.getClass().getMethod("setName", String.class);
//指定set方法
method.invoke(bean, "sad");
//无参方法
Method method2 = bean.getClass().getMethod("getName");
obj = method2.invoke(bean);
} catch (NoSuchMethodException e) {
// 没有该方法
e.printStackTrace();
} catch (SecurityException e) {
// 权限
e.printStackTrace();
} catch (IllegalAccessException e) {
// 不循序访问 属性或者方法为私有
e.printStackTrace();
} catch (IllegalArgumentException e) {
// 参数传出异常
e.printStackTrace();
} catch (InvocationTargetException e) {
// 发射异常
e.printStackTrace();
}
return obj;
}
测试类:
package com.tt.reflect;
public class MainTest {
public static void main(String[] args) {
ReflectTest r = new ReflectTest();
//注意点,如果bean里面有其他的构造函数,则需要自己写明 无惨构造函数否在会报错
TestBean bean = r.getBean();
System.out.println("bean:"+bean.getStatus());
TestBean paramBean = r.getParamBean();
System.out.println("paramBean:"+paramBean.getStatus());
Object reflectMethod = r.reflectMethod();
System.out.println(reflectMethod);
}
}
测试结果:
bean:锁定
paramBean:不锁定
sad
扩展思考,
1、如何简化数据库操作?
2、spring和mybatis 中有没有用到反射的例子?
3、反射有什么好处?优点在什么地方?
4、我该怎么使用反射增强写代码的效率?怎么使用反射来自己写一些常用的工具包?
-----------------------------------------------反射在平时的应用----------------------------------------------------
4、反射在平时的应用
spring IoC其实是一个很好的例子,通过配置文件 类全名 把bean放在容器里面,可以根据类全名 和参数 把bean放在容器里面。通过xml初始化bean 放在容器的过程使用了反射,感兴趣可以看一下源码。