这是this SO answer的扩展名。
注意:这不是以下内容的重复。 Why List is not a subtype of
List<Number>
but is subtype ofList<? 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>
个对象。
那么,为什么不允许这样做?
答案 0 :(得分:1)
您可能错过了树木的森林,并认为List<Pair<Object>>
与List<? super Pair<? super Number>>
相同,而不是。
List<? super Pair<? super Object>>
声明列表将包含Pair<Object>
或Pair<Object>
的超类型,可能是Object
或其他一些祖先类在Object
和Pair<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>
个对象。
这两者都是 不兼容的 类型。因此错误。