- 反射的实现主要通过以下四个类:
Class:类的对象,Constructor:类的构造方法,Field:类中的属性对象,Method:类中的方法对象
- 获取Class对象的三种方法:
Class.forName(类名全称即包含了包名),类名.class,实例.getClass()
注意:类的加载信息只会在永久代里留存一份,所以同一个对象不管是通过forName还是class或者getClass方法获得的Class对象,都是同一个
- 几种情况下的使用:
有参构造方法获取实例
Class c = Class.forName(类名全称);
Constructor con = c.getConstructor(String.class, int.class,String.class);//此处对应构造函数参数为(String a, int b,String c)
Object obj = con.newInstance("xxx", x, "xxx");//取得有参构造方法对象的实例
无参构造方法获取实例
Object obj=Class.forName(类名全称).newInstance();//通过反射获取无参构造方法对象的实例
修改字段内容
JDK1.8中String类:
String str="abc";
Field field=str.getClass().getDeclaredField("value");//String类中的value字段(char数组)
field.setAccessible(true);//将该字段设置为可以访问
char[] ch=(char[])field.get(str);//从str中取得这个对象(char数组)
ch[1]='d';//将char数组中下标为1的位置上设置为d
//此时打印str显示为 adc
调用其他方法
JDK1.8中Method类中invoke方法源码,可知,第一个参数是要对其进行操作的实例(或者说,要调用的方法的名字所隶属的对象实体),必须有,如果参数为基本类型数据,必须转换为相应的包装类型的对象,invoke()方法的返回值总是对象;第二个不定参数为调用的方法的那些参数,也许有也许没有,总之,都不能是基本数据类型
String str = "hello";
Method m = str.getClass().getMethod("toUpperCase");
m.invoke(str); // 此处返回HELLO
- 常用情景
框架设计中,不管是SSH还是SSM,或者JUnit等都有较多使用,而且一般需要结合xml或者properties来使用
例如:
工厂模式+单例+反射+properties
前提:properties中两个实现类都继承了同一个接口BankDaoInterface,只是实现方式不同
注意:除了工厂类,这两个dao也采用了单例模式
properties文件:
工厂类:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 工厂模式
* @author LuoPiao
*
*/
public class BankDaoFactory {
//安全的单例模式
private static volatile BankDaoFactory baf = null;
private BankDaoFactory() {//防止乱实例化,构造方法私有化
}
public static BankDaoFactory getInstance() {
if (baf == null) {//双层检查
synchronized(BankDaoFactory.class){//同步
if(baf == null){
baf=new BankDaoFactory();
}
}
}
return baf;
}
//获取操作对象
public Object choose(String shortName){
Object obj=null;
//对文件进行操作,获取类名全称
Properties p=new Properties();
try {
p.load(new FileInputStream("src/classInfo.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String fullName=p.getProperty(shortName);//拿到完整名称
try {
Method method=Class.forName(fullName).getMethod("getInstance");//拿到需要调用的单例对象的方法
obj=method.invoke(Class.forName(fullName));//调用方法,拿到返回值,此处的参数是要调用的方法隶属的对象实体,在这里它和getInstance返回值类型一致
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return obj;
}
}
其中一个dao例如:
public class SqlDaoImpl implements BankDaoInterface {
//单例模式
private static volatile SqlDaoImpl bai = null;
private SqlDaoImpl() {
}
public static SqlDaoImpl getInstance() {
if (bai == null) {
synchronized(SqlDaoImpl.class){
if(bai == null){
bai=new SqlDaoImpl();
}
}
}
return bai;
}
//实现接口定义的方法
......
}
调用:
//在需要调用的类中,声明成员变量
public static BankDaoInterface dao=null;
//在初始化方法或者构造方法中对以上变量进行赋值
BankDaoFactory bdf=BankDaoFactory.getInstance();
//dao=(BankDaoImpl) bdf.choose("BankDaoImpl");
dao=(SqlDaoImpl) bdf.choose("SqlDaoImpl");//dao层修改为使用数据库操作