Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Chaos Java

Tags:

java

generics

I use two Interfaces:

public interface Receiver<T> {

  public void receive(T obj);

  public Set<Class<? extends T>> getInterests();

}

public interface Distributor<T> extends Receiver<T> {

 public void register(Receiver<T> receiver);

}

My problem that I want to register a Distributor in a Distributor e.g. Distributor<Object> ==register==> Distributor<String>

My first thought was to change the register method to register(Receiver<? extends T> receiver). But if I want to get the Classes the receiver is intrested in the Method getInterests would return something like Set<Class<? extends ? extends T>>. Indirect I get something like Set<Class<? extends T>> but I experienced that transitiv wildcards are not possible in Java.

Got anyone an idea?

EDIT: As an example:

public void register(Receiver<? extends T> receiver){
  Set<Class<? extends T>> interests = receiver.getInterests();
  //Problem because receiver.getInterests is 
  //Set<Class<? extends ? extends T>>
  ...
}
like image 410
CRC Avatar asked Aug 25 '15 15:08

CRC


2 Answers

Your problem is that Java generics are completely invariant, unless you make them variant using ? extends or ? super wildcards.

A Set<Class<? extends T>> can only hold expressions of exactly the compile-time type Class<? extends T>. Class<String> is not the same type as Class<? extends T> (even though it is convertible to that type).

You want a set that can hold any type that is convertible to Class<? extends T>.

That would be a Set<? extends Class<? extends T>>

like image 59
SLaks Avatar answered Nov 20 '22 21:11

SLaks


You could add a helper method that uses a type variable instead of wildcard

public void register(Receiver<? extends T> receiver)
{
    register2(receiver);
}

private <S extends T> void register2(Receiver<S> receiver)
{
    Set<Class<? extends S>> interests = receiver.getInterests();
    ...
}

On the other hand, method

    public Set<Class<? extends T>> getInterests();

is probably intended to return a covariant Set, or, read-only set. Ideally wildcard should be used

    public Set<? extends Class<? extends T>> getInterests();

but I know, there are too many damn wildcards...

like image 31
ZhongYu Avatar answered Nov 20 '22 22:11

ZhongYu