6

我想从类的字符串名称实例化一个类的实例。(使用 Class.forName().newInstance()。)

问题是:我希望该实例是单例。我可以使用单例模式来做到这一点,除了 newInstance 调用类的默认构造函数,并且对于单例,该构造函数必须是“私有的”。

有解决办法吗?我可以想到一种不太优雅的方法来做到这一点(使用哈希图作为查找表..),但更喜欢更好的解决方案..

谢谢,

4

5 回答 5

8

一个经典的单例也有一个静态的 getInstance() 方法——通过反射而不是使用 newInstance() 来调用它。是的,这是更多的工作,但就是这样......

或者你可以使用setAccessible()调用私有构造函数,但是你会破坏单例并下地狱。

第三,您可以完全避免使用 Singleton 并找到更好的解决方案(通常有)。

于 2009-07-14T20:17:48.140 回答
8

您可以使用反射来获取对类的静态工厂方法的引用,然后调用它。工厂方法可以强制执行单例模式

Class c = Class.forName("test.MyClass");
Method factoryMethod = c.getDeclaredMethod("getInstance");
Object singleton = factoryMethod.invoke(null, null);

接着

public class MyClass {

   private static MyClass instance;

   private MyClass() { 
      // private c'tor 
   }

   public static synchronized MyClass getInstance() {
      if (instance == null) {
         instance = new MyClass();
      }
      return instance:
   }
}

警告:单例设计模式可能对您的长期健康有害。

于 2009-07-14T20:20:08.650 回答
2

您必须知道构造对象的单例类的方法名称。如果它被称为“instance()”,你可以做类似的事情

Class c = Class.forName("MySingleton");
Method m = c.getDeclaredMethod("instance",null);
MySingleton singleton = m.invoke(null,null);
于 2009-07-14T20:21:33.500 回答
1

您可以使用枚举并为每个枚举命名一个 HashMap。或者你可以使用一些依赖注入框架来获得一个单一的东西(Guice?)

编辑好的,我也加入了一个代码示例:

package tests;
public class EnumSingleton {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName("tests.Singleton1");
        Operation instance = Operation.class.cast(c.getEnumConstants()[0]);
        System.out.println(instance.getTHEAnswer());

        c = Class.forName("tests.Singleton2");
        instance = Operation.class.cast(c.getEnumConstants()[0]);
        System.out.println(instance.getTHEAnswer());
    }
}
interface Operation {
    int getTHEAnswer();
}
enum Singleton1 implements Operation {
    INSTANCE;
    @Override
    public int getTHEAnswer() {
        return 42;
    }
}
enum Singleton2 implements Operation {
    INSTANCE;
    @Override
    public int getTHEAnswer() {
        return 84;
    }
}

而且它安全无恙。编辑现在有了一些意义。

于 2009-07-14T20:16:19.453 回答
0

你可以依赖静态工厂方法的存在吗?它会依赖于某种命名约定方式,但这会起作用。

底线:如果要知道一个类是单例的,那么它必须对该监管负责。因此,它必须符合该模式的某些实现,如果您想要在这些类中进行动态选择,那么您需要能够预测“工厂”方法。

于 2009-07-14T20:21:44.793 回答