为什么Foo <string>被认为是Foo <! - 的子类型(扩展)? extends Object - >?

时间:2015-08-09 09:09:13

标签: java generics

这是this SO answer的扩展名。

  

注意:这不是以下内容的重复。 Why List is not a subtype of List<Number> but is subtype of List<? extends Number>?,也没有任何标记重复的问题。让我解释一下。

实际问题是(编辑以删除不必要的代码),

void wildcardsMethod(List<? super Pair<? super Number>> list) {}

//... From some method.
    List<Pair<Object>> list = null;
    wildcardsMethod(list);
    // Error: wildcardsMethod(List<? super Pair<? super Number>>) is not applicable for the arguments (List<Pair<Object>>)

上述内容无效

答案是类似于(如果我没有被误解),

  

Pair<Object>Pair<? super Number>子类型,因此无法用于代替<? super Pair<>>

在这种情况下,我不理解它。我认为它只是一个Pair对象,我们应该可以使用它代替<? extends Pair<>><? super Pair<>>。但它在后者中并不起作用。

有人可以解释为什么它被视为子类型,从而将其仅限于extends而非super

编辑:

为了解释一下,让我们看看为什么我们会采用这种方法(考虑PECS),

void wildcardsMethod(List<? super Pair<? super Number>> list) {}

您将使用添加 Pair<Number>对象来传递list

在这种情况下,List<Pair<Object>>是一个有效的列表,可以接受Pair<Number>个对象。

那么,为什么不允许这样做?

3 个答案:

答案 0 :(得分:1)

您可能错过了树木的森林,并认为List<Pair<Object>>List<? super Pair<? super Number>>相同,而不是

List<? super Pair<? super Object>>声明列表将包含Pair<Object>Pair<Object>超类型,可能是Object或其他一些祖先类在ObjectPair<T>之间。 List<Pair<Object>>声明只有 Pair个对象或可被视为Pair的对象才会出现在该类中。

界限朝不同方向发展。你隐含地通过第一个声明获得List<? extends Pair<? super Object>>

你可以合理地做到这一点的唯一方法是,你传递的列表也以类似的方式绑定。也就是说,您希望传递List<? super Pair<? super Number>>

答案 1 :(得分:0)

当你说“A是B的子类型”时,根据定义的含义是,A类型的每个对象也是B类型的对象。现在,如果你声明一个变量, Foo<? extends Object> x;,这意味着x可以引用的对象恰好是Foo<something>类型的对象(其中something扩展Object)。显然,它包括Foo<String>类型的对象。

因此,每个Foo<String>也是Foo<? extends Object> - 因此根据定义,Foo<String>Foo<? extends Object>的子类型。

同样,每个Pair<Object>也是Pair<? super Number> - 因此根据定义,Pair<Object>Pair<? super Number>的子类型。

答案 2 :(得分:0)

在考虑了Makoto的答案之后,我明白了它的含义。

注意:我正在以一种我可以很容易理解的格式撰写这个答案以供将来参考(虽然他将是接受的答案)

假设我们有这样定义的方法(考虑PECS),

    let information: ABRecord = ABPersonCreate().takeRetainedValue()

    let address: ABMutableMultiValueRef = ABMultiValueCreateMutable(ABPropertyType(kABMultiDictionaryPropertyType)).takeUnretainedValue()

    var keys = [CFStringRef]()
    var values = [CFStringRef]()

    keys.append(kABPersonAddressStreetKey)
    keys.append(kABPersonAddressCityKey)
    keys.append(kABPersonAddressStateKey)
    keys.append(kABPersonAddressZIPKey)
    keys.append(kABPersonAddressCountryKey)
    keys.append(kABPersonAddressCountryCodeKey)

    Note: country code left out

    values.append(s["kABPersonAddressStreetKey"]!! as NSString)
    values.append(s["kABPersonAddressCityKey"]!! as NSString)
    values.append(s["kABPersonAddressStateKey"]!! as NSString)
    values.append(s["kABPersonAddressZIPKey"]!! as NSString)
    values.append(s["kABPersonAddressCountryKey"]!! as NSString)
    values.append(s["kABPersonAddressCountryCodeKey"]!! as NSString)

    let dict = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)

    let scanned = ABUnknownPersonViewController()

    let identifier = ABMultiValueIdentifier()

    ABMultiValueAddValueAndLabel(address, dict, kABHomeLabel, &identifier)

    ABRecordSetValue(information, kABPersonAddressProperty, address, nil)

我们用这个参数调用方法( 假设它被允许 ),

void wildcardsMethod(List<? super Pair<? super Number>> list) {
    Pair<Number> pairOfNumbers = new Pair<Number>();
    list.add(pairOfNumbers);
}

现在,List<Pair<Object>> listOfPairOfObjects = new ArrayList<Pair<Object>>(); wildcardsMethod(listOfPairOfObject); 对象已添加到Pair<Number>

另请注意, PECS的规则仅适用于listOfPairOfObjects中的list引用,而不适用于wildcardsMethod引用。

因此我能做到,

listOfPairOfObjects

现在,由于Pair<Object> pairOfObjects = listOfPairOfObjects.get(0); 已添加到方法的列表中,我希望Pair<Number>引用时会收到Pair<Number>个对象。

这两者都是 不兼容的 类型。因此错误。