Java 泛型强制执行兼容的通配符

2022-09-01 01:22:36

我有这些课程。

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

我有一个使用2个泛型类型的类

public class Connection<W, S> {}

其中 W 是 Wire type,S 是 Socket type。

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

我尝试这样做:

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

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在这里已经很好地解释了)

如何强制执行编译时检查以确保套接字和电线具有相同的颜色?


答案 1

似乎最好参数化并使用颜色: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

答案 2

作为Tagir Valeev答案的一个小变体:你可以通过使其构造函数(或者包可见)来摆脱类的第三个泛型参数,并提供一个用于创建实例的工厂方法,以确保给定的类型和类型相同:ConnectionprivateConnectionColorWireSocket

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

推荐