通过反射查看类信息
Java程序中的许多对象在运行时都会出现两种类型:编译时类型和运行时类型,例如代码:Person p=newStudent();,这行代码将会生成一个p变量,该变量的编译时类型为Person,运行时类型为Student
程序需要在运行时发现对象和类的真实信息,有以下两种方案:
假设在编译时和运行时都完全知道类型的具体信息,在这种情况下,可以先使用instanceof运算符进行判断,再利用强制类型转换将其转换成其运行时类型的变量即可
编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,这就必须使用反射
获取 class 对象
在Java程序中获得Class对象通常有如下三种方式:
使用Class类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整包名)
调用某个类的class属性来获取该类对应的Class对象,如 Person.class
调用某个对象的getClass()方法
如果程序只能获得一个字符串,例如"java.lang.String",若需要获取该字符串对应的Class对象,则只能使用第一种方式
一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了
通过反射创建对象
通过反射来生成对象需要先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例
在很多Java EE框架中都需要根据配置文件信息来创建Java对象,从配置文件读取的只是某个类的字符串类名,程序需要根据该字符串来创建对应的实例,就必须使用反射
实例:通过读取配置文件,动态创建对象实例
配置文件:
a=java.util.Date
b=javax.swing.JFrame
代码实现:
public class ObjectPoolFactory {
private final Map objectPool = new HashMap<>();
private Object createObject(String clazzName) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class> clazz = Class.forName(clazzName);
return clazz.getConstructor().newInstance();
}
public void initPool(String fileName) {
try (FileInputStream fis = new FileInputStream(fileName)) {
Properties props = new Properties();
props.load(fis);
for (String name : props.stringPropertyNames()) {
objectPool.put(name, createObject(props.getProperty(name)));
}
} catch (Exception e) {
System.out.println("读取 " + fileName + " 异常");
}
}
public Object getObject(String name) {
return objectPool.get(name);
}
public static void main(String[] args) {
ObjectPoolFactory pf = new ObjectPoolFactory();
pf.initPool("/Users/senlongzhong/code/demo/javaDemo/src/main/java/crazy/chart18/section04/obj.txt");
System.out.println(pf.getObject("a"));
System.out.println(pf.getObject("b"));
}
}
通常没有必要使用反射来创建对象,毕竟通过反射创建对象时性能要稍低一些。实际上,只有当程序需要动态创建某个类的对象时才会考虑使用反射,通常在开发通用性比较广的框架、基础平台时可能会大量使用反射