如何在java中参数化generics单例

我有下一个问题。 我有一个界面:

public interface Worker { public void start(Class taskClass); } 

和单接口实现此接口:

 public final class Listener implements Worker { private Listener() {} @Override public void start(Class taskClass) { ... } public static Listener getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { public static final Listener INSTANCE = new Listener(); } } 

我的问题是,我可以通过这种方式得到单例实例:

 Worker listener = Listener.getInstance(); 

还是类型安全吗? 什么时候不能,如何在单例实例中使用generics?

所有generics都在运行时被剥离。

这意味着无论generics是什么,你只会有一个static class SingletonHolder和一个INSTANCE

为了解决这个问题,如果有意义,你可以拥有“多个单身人士”。 您必须添加某种注册,因此如果您尝试获取一个尚未存在的注册,请在返回之前创建并存储它。 请注意,这不是编译的,可能存在一些问题,但基本方法仍然相同。

 public final class Listener implements Worker { private Listener() {} @Override public void start(Class taskClass) { ... } public static Listener getInstance(Class clazz) { return SingletonHolder.INSTANCE.get(clazz); } private static class SingletonHolder { private static final Map,Listener INSTANCE = new ...; } } 

只是

 public final class Listener implements Worker { private Listener() {} @Override public void start(Class taskClass) { ... } } 

显然,监听器实例可以接受任何Thread子类。

 Worker worker = Listener.getInstance(); worker.start( MyThread.class ); 

如果要限制类型,为了阐明worker是Thread子类,则不能

 Worker worker = Listener.getInstance(); // error[1] 

但是你可以

 Worker worker = Listener.getInstance(); worker.start( MyThread.class ); // works for all Thread subclasses. worker.start( SomeRunnable.class ); // error; only for Thread subclasses. 

如果我们讨厌通配符(我们这样做),我们可能会想要明确一个Worker也是一个Worker ; error[1]只是愚蠢的限制。

擦除的一个好处是,我们可以建立这种协方差。

 @SuppressWarnings("unchecked") Worker worker = (Worker)(Worker) Listener.getInstance(); 

我们知道演员阵容对所有意图和目的都是安全的。

如果需要经常这样做,我们可以将协方差转换移动到getInstance()以便于使用:

 Worker worker = Listener.getInstance(); public final class Listener implements Worker static Listener instance = new Listener(); // it is safe to cast Worker to any Worker // as long as B is subtype of A @SuppressWarnings("unchecked") static public  Worker getInstance() return (Worker)(Worker)instance;