繁体   English   中英

Java通用捕获和可比较

[英]Java generic captures and comparable

这是一个容器的实现,可以与具有兼容键的任何其他容器进行比较。 我在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

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

让我们从compareTo方法向后工作。 您想要与容器进行比较,并且希望使用键进行比较(因此key.compareTo(o.key))。 这意味着您的o必须生成Key ,并且您的key必须使用Key 第一部分意味着你的方法声明应该是public int compareTo(Container<? extends Key, ?> o) ,这意味着你应该实现Comparable<Container<? extends Key, ?>> Comparable<Container<? extends Key, ?>> 第二部分意味着你的Key应该是一个Comparable<? super 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。 你只需要一个可以生成一些可以使用Key密钥的Container

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

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

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

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

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

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


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

例如,您正在尝试创建它,以便可以将Container<String>Container<Object>进行比较。 但是反过来做比较甚至不会编译 这种情况对您有效吗? 我希望可比性是对称的,并且让我a.compareTo(b)困惑的是a.compareTo(b)是1,但是b.compareTo(a) 返回-1但反而拒绝编译。 这就是为什么,例如Double实现Comparable<Double>而不是Comparable<? super 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);
    }
}

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

    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) ,但我没有设法写那个必要的通用约束...... :(

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

只是摆脱“超级”,它将编译。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM