简体   繁体   English

Java通用捕获和可比较

[英]Java generic captures and comparable

This is an implementation of a container that can be compared to any other container with a compatible key. 这是一个容器的实现,可以与具有兼容键的任何其他容器进行比较。 I have a weird error using generics in Java, any ideas? 我在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);
        }
    }
    ...

This is the error: 这是错误:

    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: Producer extends, Consumer super. PECS:制作人延伸,消费者超级。

Let's work backwards from the compareTo method. 让我们从compareTo方法向后工作。 You want to compare to a container, and you want to compare using the keys (hence key.compareTo(o.key)). 您想要与容器进行比较,并且希望使用键进行比较(因此key.compareTo(o.key))。 This means that your o must produce a Key , and your key must consume a Key . 这意味着您的o必须生成Key ,并且您的key必须使用Key The first part means your method declaration should be public int compareTo(Container<? extends Key, ?> o) , which then means you should implement Comparable<Container<? extends Key, ?>> 第一部分意味着你的方法声明应该是public int compareTo(Container<? extends Key, ?> o) ,这意味着你应该实现Comparable<Container<? extends Key, ?>> Comparable<Container<? extends Key, ?>> . Comparable<Container<? extends Key, ?>> The second part means your Key should be a Comparable<? super Key> 第二部分意味着你的Key应该是一个Comparable<? super Key> Comparable<? super Key> , which is how you had it. 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);
    }
}

Edit: Following exactly the comments below, the declaration would be a follows. 编辑:完全按照以下评论,声明如下。 Notice the flip in the keys calling compareTo, and how Key no longer needs to implement Comparable at all. 注意调用compareTo的键中的翻转,以及Key根本不再需要实现Comparable。 You just need to take a Container that can produce some key that can consume a Key 你只需要一个可以生成一些可以使用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);
    }
}

You're simply not implementing the interface correctly. 您只是没有正确实现接口。 You define Container as implementing Comparable<Pair<? super Key, Value> 您将Container定义为实现Comparable<Pair<? super Key, Value> Comparable<Pair<? super Key, Value> . Comparable<Pair<? super Key, Value> That means that it must declare a method: 这意味着它必须声明一个方法:

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

but right now it doesn't, because it's missing the wildcard. 但是现在它没有,因为它缺少通配符。

The problem in a broader sense is with your wildcard matching. 广义上的问题是你的通配符匹配。 The ? ? means "any type that matches these bounds". 表示“匹配这些边界的任何类型”。 Critically, different instances of ? 关键的是,不同的实例? can be different concrete types ; 可以是不同的具体类型 ; this is what the "capture of" types refer to. 这就是“捕获”类型所指的内容。

Any time that you have question marks that you want to "pair up" at all, you should give that parameter a name so you can enforce the identity (eg introduce a generic parameter for the method). 任何时候你都有想要“配对”的问号,你应该给该参数一个名称,这样你就可以强制执行该身份(例如为该方法引入一个通用参数)。 Whenever you use a ? 每当你使用? , you're essentially saying that "I don't care at all what the concrete type of this parameter is", so you can't perform any operations that depend on matching parameters exactly (such as assignment). ,你基本上说,“我完全关心具体类型这个参数的是什么”,所以你不能执行依赖于精确匹配参数(如转让)的任何操作。


Edit: in a more specific sense I think your intentions are slightly off. 编辑:在更具体的意义上,我认为你的意图略有偏差。 You've tried to declare a Container on a particular Key type as comparable to a Container on a different (superclass) of Key . 您已尝试将特定Key类型上的Container声明为与另一个(超类) Key上的Container相当。 I'm not convinced this is necessarily a good idea, as it introduces some asymmetry. 我不相信这一定是个好主意,因为它引入了一些不对称性。

For instance, you're trying to make it so a Container<String> can be compared against a Container<Object> . 例如,您正在尝试创建它,以便可以将Container<String>Container<Object>进行比较。 But doing the comparison the other way round wouldn't even compile . 但是反过来做比较甚至不会编译 Does this situation seem valid to you? 这种情况对您有效吗? I'd expect comparability to be symmetric, and it would confuse me that a.compareTo(b) is 1, but b.compareTo(a) doesn't return -1 but instead refuses to compile. 我希望可比性是对称的,并且让我a.compareTo(b)困惑的是a.compareTo(b)是1,但是b.compareTo(a) 返回-1但反而拒绝编译。 This is why, for example Double implements Comparable<Double> and not Comparable<? super Double> 这就是为什么,例如Double实现Comparable<Double>而不是Comparable<? super Double> Comparable<? super Double> . Comparable<? super Double>

EDIT for plain answer: So you should get rid of those wildcards, as it's not going to be possible to compare against an arbitrary object. 编辑简单回答:所以你应该摆脱那些通配符,因为它不可能与任意对象进行比较。 Thus the definition would look like: 因此,定义看起来像:

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

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

This works, but looks like a hack: 这有效,但看起来像黑客:

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

I would certainly prefer to write key.compareTo(o.key) , but I didn't manage to write the necessary generic constraint for that... :( 我当然更喜欢写key.compareTo(o.key) ,但我没有设法写那个必要的通用约束...... :(

For some reason, Eclipse inserts "? super Type" when you create a Comparable type but that doesn't make sense (which superclass of Type will work in the compareTo() ?). 出于某种原因,Eclipse在创建Comparable类型时插入“?super Type”但是没有意义(Type的哪个超类在compareTo() ?)。

Just get rid of "? super" and it will compile. 只是摆脱“超级”,它将编译。

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

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