Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用泛型和反射的单例工厂_Java_Generics_Reflection_Singleton_Factory - Fatal编程技术网

Java 使用泛型和反射的单例工厂

Java 使用泛型和反射的单例工厂,java,generics,reflection,singleton,factory,Java,Generics,Reflection,Singleton,Factory,OrderDBManager、UserDBManager、ProductDBManager扩展DBManager。 我正在尝试创建一个单例DBManager工厂 获取不同DBManager类型类的实例 但我在使用泛型返回用户想要的确切DBManager类型类的实例时遇到了一个问题。现在它只对DBManager本身有效。 谢谢你的帮助 public class DBManagerFactory { private static final Map<String, DBManage

OrderDBManager、UserDBManager、ProductDBManager扩展DBManager。 我正在尝试创建一个单例DBManager工厂 获取不同DBManager类型类的实例

但我在使用泛型返回用户想要的确切DBManager类型类的实例时遇到了一个问题。现在它只对DBManager本身有效。 谢谢你的帮助

public class DBManagerFactory {

     private static final Map<String, DBManager> instances = new HashMap<>();

     private static final String DB_MANAGER_PACKAGE_NAME = "ua.Test.db.";

     public static DBManager getInstance(Class<? extends DBManager> dbManagerClass) {
            String dbManagerClassName = dbManagerClass.getSimpleName();
            DBManager dbManager = instances.get(dbManagerClassName);

            if(dbManager == null){
                Class clazz = Class.forName(DB_MANAGER_PACKAGE_NAME + dbManagerClassName);
                dbManager = (DBManager)clazz.newInstance();
                instances.put(dbManagerClassName, dbManager);    
            }
            return dbManager;                                             
     }}                                                                
公共类DBManagerFactory{
私有静态最终映射实例=new HashMap();
私有静态最终字符串DB\u MANAGER\u PACKAGE\u NAME=“ua.Test.DB。”;

publicstaticdbmanager getInstance(Class如果需要获取显式返回类型,则可以使用,如下所示:

class Base {}

class A extends Base {}

class B extends Base {}

class InitializationFailedException extends RuntimeException {
    public InitializationFailedException(Throwable cause) {
        super(cause);
    }
}

class Factory {

    private static Logger log = LoggerFactory.getLogger(Factory.class);

    private static final ConcurrentHashMap<Class<? extends Base>, Base> instances = new ConcurrentHashMap<>();

    public static  <T extends Base> T getInstance(Class<T> tClass) {
        if (tClass == null) {
            throw new NullPointerException();
        }
        return (T) instances.computeIfAbsent(tClass, (tClass1) -> {
            try {
                return tClass1.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                log.error("Unable to create singleton value for " + tClass1.getCanonicalName(), e);
                throw new InitializationFailedException(e);
            }
        });
    }

}
对于您的问题,方法签名可以如下所示:

public static <T extends DBManager> T getInstance(Class<T> dbManagerClass);
private static final Map<Class<? extends DBManager>, DBManager> instances = new HashMap<>();
publicstatict getInstance(类dbManagerClass);
实例映射应如下所示:

public static <T extends DBManager> T getInstance(Class<T> dbManagerClass);
private static final Map<Class<? extends DBManager>, DBManager> instances = new HashMap<>();
私有静态最终映射
但是我在使用泛型返回精确的
用户想要的DBManager类型类

要在方法中返回特定类,应指定一个作用域方法参数化类型,该类型允许类的客户端指定方法应返回的类型。

您可以通过以下方式声明该方法:

public static <T extends DBManager> T getInstance(Class<T> dbManagerClass)  {
DBManager instance = DBManagerFactory.getInstance(DBManager.class);
DBManagerChild child = DBManagerFactory.getInstance(DBManagerChild.class);
最后,检索类的方法是:

Class clazz = Class.forName(DB_MANAGER_PACKAGE_NAME + dbManagerClassName);
不需要,因为您已经将类作为方法的参数。
直接使用即可。

以下是实现此解决方案的示例代码:

public class DBManagerFactory {

    private static final Map<String, DBManager> instances = new HashMap<>();

    public static <T extends DBManager> T getInstance(Class<T> dbManagerClass)  {

      final String dbManagerClassName = dbManagerClass.getSimpleName();

      T dbManager = dbManagerClass.cast(instances.get(dbManagerClassName));

      if (dbManager == null) {
        try {
          dbManager =  dbManagerClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
          e.printStackTrace(); // or better log it
          throw new RuntimeException("faillure during reflection instantiation for class " + dbManagerClass.getName(), e);
        }
        instances.put(dbManagerClassName, dbManager);
      }

      return dbManager;
    }   

}

好的。那么映射声明应该是什么样子的呢?获取显式返回类型的逻辑是可以的,只是要小心HashMap,它不是同步的。在生产环境中,应该修改此代码以避免破坏HashMap。@LuigiRubino问题是关于泛型的,而不是关于线程安全或任何其他重要但独立的主题
抛出异常
?有一个反模式。@LewBloch你是对的。但是,我个人不喜欢答案包含大量“生产就绪”不必要的代码,这会带来更多的混乱而不是价值。无论如何,修改了答案。这个
类的目的是什么。forName(DB_MANAGER_PACKAGE_NAME+dbManagerClassName)
?调用方已经向您提供了一个
对象。您不应该使用未经检查的强制转换,如
(T)…
。相反,如果OP使用了
dbManagerClass.newInstance(),请使用
dbManagerClass.cast(…)
。作为旁注
,返回的引用的类型已经是
T
。OP处理名称的整个过程看起来都是错误的…@Holger您完全正确。我会避免更改OP检索类的方式:
class clazz=class.forName(DB_MANAGER\u PACKAGE\u NAME+dbManagerClassName)
正如您所注意到的,它没有正确使用。我只是修改了它,以便给出更好、更全面的答案。