Java通用捕获和可比较

时间:2010-08-10 15:13:33

标签: java generics

这是一个容器的实现,可以与具有兼容键的任何其他容器进行比较。我有一个奇怪的错误,使用Java中的泛型,任何想法?

    private static class Container
    <Key extends Comparable<? super Key>, Value>
    implements Comparable<Container<? super Key, ?>> 
    {
        public Key key;
        public Value value;
        public Container(Key k, Value v) {
            key = k;
            value = v;
        }
        public int compareTo(Container<? super Key, ?> o) {
            return key.compareTo(o.key);
        }
    }
    ...

这是错误:

    compareTo(capture#98 of ? super Key) in
    java.lang.Comparable<capture#98 of ? super Key> cannot be applied to 
    (java.lang.Comparable<? super capture#822 of ? super Key>)
            return key.compareTo(o.key);
                      ^
    1 error

4 个答案:

答案 0 :(得分:5)

PECS:制作人延伸,消费者超级。

让我们从compareTo方法向后工作。您想要与容器进行比较,并且希望使用键进行比较(因此key.compareTo(o.key))。这意味着您的o必须生成Key,而您的key必须消费Key。第一部分意味着您的方法声明应为public int compareTo(Container<? extends Key, ?> o),这意味着您应该实现Comparable<Container<? extends Key, ?>>。第二部分意味着您的Key应该是Comparable<? super Key>,这就是您拥有它的方式。

private static class Container<Key extends Comparable<? super Key>, Value>
                    implements Comparable<Container<? extends Key, ?>> {

    public Key key;
    public Value value;

    public Container(Key k, Value v) {
        key = k;
        value = v;
    }

    public int compareTo(Container<? extends Key, ?> o) {
        return key.compareTo(o.key);
    }
}

编辑: 完全遵循以下评论,声明如下。注意调用compareTo的键中的翻转,以及Key不再需要实现Comparable的方式。您只需要使用Container来生成一些可以使用Key

的密钥
private static class Container<Key, Value> implements
        Comparable<Container<? extends Comparable<? super Key>, ?>> {

    //fields and constructors...

    public int compareTo(Container<? extends Comparable<? super Key>, ?> o) {
        return -o.key.compareTo(key);
    }
}

答案 1 :(得分:1)

您只是没有正确实现界面。您将Container定义为实施Comparable<Pair<? super Key, Value>。这意味着它必须声明一个方法:

public int compareTo(Comparable<Pair<? super Key, Value> o)

但是现在它没有,因为它缺少通配符。

广义上的问题在于您的通配符匹配。 ?表示“匹配这些边界的任何类型”。重要的是,? 的不同实例可以是不同的具体类型;这就是“捕获”类型所指的内容。

如果您有任何想要“配对”的问号,您应该为该参数指定一个名称,以便您可以强制执行该身份(例如,为该方法引入一个通用参数)。每当你使用?时,你基本上都会说“我不关心所有这个参数的具体类型是什么”,所以你不能执行任何操作完全依赖于匹配参数(例如赋值)。


编辑:从更具体的意义上说,我认为你的意图略有偏差。您尝试在特定Container类型上声明Key,与Key的不同(超类)上的Container相比较。我不相信这一定是个好主意,因为它引入了一些不对称性。

例如,您正试图将Container<String>Container<Object>进行比较。但是反过来做比较甚至不会编译。这种情况对您有效吗?我希望可比性是对称的,a.compareTo(b)为1会让我感到困惑,但b.compareTo(a) 不会返回-1,而是拒绝编译。这就是为什么,例如Double实现Comparable<Double>而不是Comparable<? super Double>

编辑以获得简单的答案:所以你应该摆脱那些通配符,因为它不可能与任意对象进行比较。因此,定义看起来像:

private static class Container
<Key extends Comparable<Key>, Value>
implements Comparable<Container<Key, ?>>
{
    ...

    public int compareTo(Container<Key, ?> o) {
        return key.compareTo(o.key);
    }
}

答案 2 :(得分:0)

这很有效,但看起来像是黑客:

    private static class Container
    <K extends Comparable<? super K>, Value>
    implements Comparable<Container<? extends Comparable<? super K>, ?>>
    {
        public K key;
        public Value value;
        public Container(K k, Value v) {
            key = k;
            value = v;
        }
        public int compareTo(Container<? extends Comparable<? super K>, ?> o) {
            return -o.key.compareTo(key);
        }
    }

我当然更愿意写key.compareTo(o.key),但我没有设法为此编写必要的通用约束...... :(

答案 3 :(得分:-3)

出于某种原因,Eclipse在您创建Comparable类型时插入“?super Type”但是没有意义(Type的哪个超类将在compareTo()中起作用?)。

摆脱“超级”,它会编译。