繁体   English   中英

如何在java中参数化泛型单例

[英]How parametrize generic singleton in java

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

public interface Worker<T> {
    public void start(Class<? extends T> taskClass);
}

和单接口实现此接口:

public final class Listener<T extends Runnable> implements Worker<T> {
    private Listener() {}

    @Override
    public void start(Class<? extends T> taskClass) { ... }

    public static Listener getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        public static final Listener INSTANCE = new Listener();
    }
}

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

Worker<Thread> listener = Listener.getInstance();

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

所有泛型都在运行时被剥离。

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

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

public final class Listener<T extends Runnable> implements Worker<T> {
    private Listener() {}

    @Override
    public void start(Class<? extends T> taskClass) { ... }

    public static Listener getInstance(Class<T> clazz) {
        return SingletonHolder.INSTANCE.get(clazz);
    }

    private static class SingletonHolder {
        private static final Map<Class<? extends Runnable>,Listener<? extends Runnable> INSTANCE = new ...;
    }
}

只是

public final class Listener implements Worker<Runnable> {
    private Listener() {}

    @Override
    public void start(Class<? extends Runnable> taskClass) { ... }

}

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

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

如果要限制类型,以澄清worker是Thread子类,则不能

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

但是你可以

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

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

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

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

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

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

Worker<Thread> worker = Listener.getInstance();

public final class Listener implements Worker<Runnable> 

    static Listener instance = new Listener();

    // it is safe to cast Worker<A> to any Worker<B>
    // as long as B is subtype of A

    @SuppressWarnings("unchecked")

    static public <T extends Runnable> Worker<T> getInstance()

        return (Worker<T>)(Worker)instance;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM