Javagenerics强制执行兼容通配符

我有这些课程。

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

我有一个类使用2个genericstypes

 public class Connection<W, S> {} 

其中W是导线types,S是socketstypes。

我试图强制编译时检查,以确保套接字和电线具有相同的颜色。

我试过这样做:

 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 {} 

但是这并不能确保所使用的Color对于两个generics都是相同的,并且仍然让我这样做:

 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>(); } } 

(为什么发生这种情况已经在这里由Radiodef精彩地解释)

我怎样才能执行编译时检查,以确保套接字和电线具有相同的颜色?

似乎最好用颜色参数化SocketWire

 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> {} 

通过这种方式,您可以在Connection引入更多的通用参数:

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

像这样使用它:

 new Connection<Red, RedWire, RedSocket>(); // ok new Connection<Green, GreenWire, GreenSocket>(); // ok new Connection<Green, GreenWire, RedSocket>(); // error 

作为Tagir Valeev答案的一个小的变化:通过使它的构造函数是private (或者可能包是可见的),你可能会抛弃Connection类的第三个通用参数,并提供一个创buildConnection实例的工厂方法,以确保Colortypes与给定的WireSockettypes相同:

 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 } } 

试图混合一个任意适当的像“颜色”是一个典型的触发整个inheritancevs组成aka。 是一个vs一个辩论。 像Java这样的语言的普遍看法是,在大多数一般情况下,人们应该偏好组合而不是inheritance,以避免像通配符那样的事情。 其他语言可能会提供更多的面向方面编程的方式

虽然其他答案可能会帮助您实现正确的generics,但我build议您阅读关于该主题的维基百科页面,并考虑您是否确实需要在编译时强制执行颜色匹配,或者是否使用运行时构造函数执行此项工作。