Java Generics provides wildcard compatibility

I have these classes.

class RedSocket {} class GreenSocket {} class RedWire {} class GreenWire {} 

I have a class that uses 2 generic types

 public class Connection<W, S> {} 

where W is the type of wire and S is the type of Socket.

I am trying to provide a compile time check to make sure that the socket and wire are the same color.

I tried to do this:

 public class Connection<W extends Wire & Color, S extends Socket & Color> {} interface Color {} interface Red extends Color {} interface Green extends Color {} interface Socket {} interface Wire {} class RedSocket implements Socket, Red {} class GreenSocket implements Socket, Green {} class RedWire implements Wire, Red {} class GreenWire implements Wire, Green {} 

But this does not really guarantee that the Color used is the same for both types, but still allows me to do this:

 public class Connection<W extends Wire & Color, S extends Socket & Color> { public static void main(String[] args) { new Connection<RedWire, GreenSocket>(); new Connection<GreenWire, RedSocket>(); } } 

(Why this happens was brilliantly explained by Radiodef here )

How can I provide compile time checking to make sure the socket and wire are the same color?

+42
java generics
Aug 27 '15 at 8:08
source share
3 answers

It seems that it is better to parameterize Socket and Wire with color:

 interface Socket<C extends Color> {} interface Wire<C extends Color> {} class RedSocket implements Socket<Red> {} class GreenSocket implements Socket<Green> {} class RedWire implements Wire<Red> {} class GreenWire implements Wire<Green> {} 

Thus, you can enter another common parameter in Connection :

 public class Connection<C extends Color, M extends Wire<C>, Q extends Socket<C>> {...} 

And use it as follows:

 new Connection<Red, RedWire, RedSocket>(); // ok new Connection<Green, GreenWire, GreenSocket>(); // ok new Connection<Green, GreenWire, RedSocket>(); // error 
+55
Aug 27 '15 at 8:16
source share

As a slight variation of the answer Tagir Valeev : you can get rid of the third general parameter of the Connection class by creating its private constructor (or, possibly, the package is visible), and suggest a factory method for creating Connection instances, which ensures that the Color type is the same for the given types Wire - and Socket :

 class Connection< W extends Wire<? extends Color>, S extends Socket<? extends Color>> { static <C extends Color, W extends Wire<C>, S extends Socket<C>> Connection<W, S> create() { return new Connection<W, S>(); } // Private constructor private Connection() {} } interface Color {} interface Red extends Color {} interface Green extends Color {} interface Socket<C extends Color> {} interface Wire<C extends Color> {} class RedSocket implements Socket<Red> {} class GreenSocket implements Socket<Green> {} class RedWire implements Wire<Red> {} class GreenWire implements Wire<Green> {} public class CompatibleGenericsTest { public static void main(String[] args) { Connection<RedWire, RedSocket> c0 = Connection.create(); // ok Connection<GreenWire, GreenSocket> c1 = Connection.create(); // ok Connection<GreenWire, RedSocket> c2 = Connection.create(); // error } } 
+35
Aug 27 '15 at 9:18
source share

Trying to mix randomly, like β€œColor,” is a typical trigger for all inheritance and composition. is-a vs has-debate. The general wisdom for a language such as Java is that in most cases, preference should be given to composition over inheritance in order to avoid things like complex wildcards. Other languages ​​may offer more in the way of aspect-oriented programming.

While other answers may help you achieve the right generics, I would suggest reading the wikipedia page on this subject and thinking about whether you really need to ensure color matching at compile time or to check the runtime constructor.

+3
Aug 28 '15 at 15:55
source share



All Articles