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精彩地解释)
我怎样才能执行编译时检查,以确保套接字和电线具有相同的颜色?
似乎最好用颜色参数化Socket
和Wire
:
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
实例的工厂方法,以确保Color
types与给定的Wire
和Socket
types相同:
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议您阅读关于该主题的维基百科页面,并考虑您是否确实需要在编译时强制执行颜色匹配,或者是否使用运行时构造函数执行此项工作。