Java 返回Class.forName而不是新实例
我在一个旧项目中发现了这段代码Java 返回Class.forName而不是新实例,java,reflection,factory,Java,Reflection,Factory,我在一个旧项目中发现了这段代码 public abstract class AireBatchDaoFactory { public static final String ORACLE_FACTORY = "airebatch.oracle.OracleDaoFactory"; public static AireBatchDaoFactory getFactory(String factory) throws SQLException { try
public abstract class AireBatchDaoFactory {
public static final String ORACLE_FACTORY = "airebatch.oracle.OracleDaoFactory";
public static AireBatchDaoFactory getFactory(String factory) throws SQLException
{
try {
return (AireBatchDaoFactory) Class.forName(factory).newInstance();
}
catch (Exception e) {
throw new SQLException("error msg");
}
}
public abstract AireBatchDao getAireBatchDao() throws SQLException;}
我想了解一下我们之间的具体区别
return (AireBatchDaoFactory) Class.forName(factory).newInstance();
及
仔细看这个方法
getFactory(String factory)
您将收到类名作为参数。你不能写字
factory factory = new factory(); // error.
在哪里
Class.forName(factory).newInstance();
这是有效的
简言之,您正在使用编译时没有使用的名称为类创建实例,并在运行时使用反射使用传递的名称创建实例。仔细查看该方法
getFactory(String factory)
您将收到类名作为参数。你不能写字
factory factory = new factory(); // error.
在哪里
Class.forName(factory).newInstance();
这是有效的
简而言之,您正在使用编译时不使用的名称为类创建实例,并在运行时使用反射创建传递名称的实例。区别在于
new AireBatchDaoFactory
将创建该特定类的实例(如果AireBatchDaoFactory
是接口或抽象类,则不编译)。但是factory
可以包含实现AireBatchDaoFactory
(如果是接口)或将其子类化(如果是类)的任何类的完全限定名。class.forName(factory).newInstance()
将加载由工厂
命名的类,并创建该类的新实例
对于代码库的运行时插件来说,这是一种非常常见的模式。通常,您定义插件实现的接口。然后提供一种运行时方法来指定要使用的特定类(在属性文件中,在某些其他配置中,等等),并使用Class.forName
加载该类,并使用newInstance
创建该类的实例。由于该类是在运行时确定的,因此它可能是使用它的代码的作者从未见过的,在使用它的代码之后很久才编写。因此,将它用于插件
考虑:
Plugin.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
Foo.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
Bar.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
App.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
运行
java App Foo
java App Bar
…加载
Bar
类并在其上调用doSomething
,为我们提供“我是Bar”
区别在于新的AireBatchDaoFactory
将创建该特定类的实例(如果AireBatchDaoFactory
是接口或抽象类,则不编译)但是factory
可能包含实现AireBatchDaoFactory
(如果是接口)或将其子类化(如果是类)的任何类的完全限定名。class.forName(factory)。newInstance()
将加载由factory
命名的类,并创建其新实例
对于代码库的运行时插件来说,这是一种非常常见的模式。通常,您定义插件实现的接口。然后提供一种运行时方法来指定要使用的特定类(在属性文件中,在某些其他配置中,等等),并使用Class.forName
加载该类,并使用newInstance
创建该类的实例。由于该类是在运行时确定的,因此它可能是使用它的代码的作者从未见过的,在使用它的代码之后很久才编写。因此,将它用于插件
考虑:
Plugin.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
Foo.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
Bar.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
App.java
:
interface Plugin {
void doSomething();
}
public class Foo implements Plugin {
public void doSomething() {
System.out.println("I'm Foo");
}
}
public class Bar implements Plugin {
public void doSomething() {
System.out.println("I'm Bar");
}
}
public class App {
public static final void main(String[] args) {
try {
String classToLoad = args[0];
Plugin plugin = Class.forName(classToLoad).newInstance();
plugin.doSomething();
}
catch (Exception e) {
//...handle error...
}
}
}
运行
java App Foo
java App Bar
…加载
Bar
类并在其上调用doSomething
,为我们提供“我是Bar”
您不能调用新的AireBatchDaoFactory()
用于抽象类。在您的示例中,反射用于获取名为的类的实例,该实例作为getFactory方法的参数传递。此类应扩展AireBatchDaoFactory抽象类
在这种情况下,您可以更改在运行时从中获得的AireBatchDaoFactory的实现。要了解其原因,为什么采用这种方式,您可以查看此逻辑是如何使用的。您不能调用
新的AireBatchDaoFactory()
用于抽象类。在您的示例中,反射用于获取名为的类的实例,该实例作为getFactory方法的参数传递。此类应扩展AireBatchDaoFactory抽象类
在这种情况下,您可以更改在运行时从它获得的AireBatchDaoFactory的哪个实现。要知道原因,为什么这样做,您可以看看这个逻辑是如何使用的。它被称为反射。有一个
字符串描述类的FQCN
,代码尝试转换该字符串
首先进入类
实例,然后进入该类
的一个新实例(假设使用默认构造函数)。这是从字符串创建实例的唯一方法-新建
显然在这里不起作用。只编写返回Class.forName(factory).newInstance()
可能是通用的,rest似乎是一样的。此外,捕获超级异常
并抛出SQLException
而不是ClassNotFoundException
,可能有人会在一段时间内改变这一点。即使不使用变量ORACLE\u工厂
。此外,这些工厂通常是抽象类无法实例化的SE(与您的案例一样)。强制转换是实现方法签名所必需的(也可能失败)@ankur singhal这是public static final
-其目的可能是,这是传递到API中的默认值,异常处理对于JDBC代码来说是非常正常的-在使用JDBC API时,重新调用SQLException
使处理代码一致。它被称为反射。有一个String
descripb调用类
的FQCN,该代码尝试首先将该字符串
转换为类
实例,然后转换为该类
的新实例(假定为默认构造函数)。这是onl