阅读更多
Demo d = new DerivedDromDemo(); //写代码编译时就确定了。
Demo d = Class.forName( "DerivedFromDemoButWeCantKnowHisName ").newInstance(); // 运行时再来,这个类名字可以计算得出,比如读取配置文件,只要他能完成 Demo d = (Demo) instance;操作就行。
Java 中很多 Spi 工厂类都是这种方式工作,
public abstract class Factory {
public static Factory getInstance(String name){
// 读取配置文件,查找信息。
InputStream in = Thread.getContextClassLoader().getResourceAsStream( "/config.properties ");
Properties config = new Properties();
config.load(in);
String clazz = config.getProperty(name);
//读到了一个工厂类完成具体事情, 这个类应该实现了 抽象业务方法,比如下面的 createSession(); 这样就能让你的这些代码已经写好的情况下,如果以后要扩展功能,你只需要在配置文件里添加,然后 使用 Factory.getInstace( "NewImplementationFactory ") 这种方式就可以工作了。
Factory instance = (Factory) Class.forName(clazz).newInstance());
return instance;
}
public abstract Session createSession();
}
还有一种情况比较常见,那就是 类库版本兼容性问题,比如 1.3 提供一个类,1.2 没有提供需要打补丁,那么可以 用 Class.forName() 运行时来探测存在版本,因为编译时并没有实际调用而是使用 Class.forName( 'xxx ').getMethod( 'name ').invoke(new Object[])这样的方式去调用,编译通过运行时还是要确保这个方法能找到,但是给了我们一个机会:当这个方法没有找到是我们想点别的办法,而不是让 JVM 抛出 ClassNotFoundException 或 NoClassDefError 错误。 如果不用 Class.forName 那么只要这个类找不到那么程序根本没有办法运行,你没有机会控制它的流程而只有清理现场退出了。