簡體   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