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