Просто
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 );
Если вы хотите ограничить тип, чтобы уточнить, что рабочий предназначен для подклассов 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;