简体   繁体   English

Java中的通用VS通配符

[英]generic VS wildcards in Java

I have these two methods under a generic class: 我在泛型类下有这两种方法:

public class Container<S> {
    public void f2(List<Object> l1, List<?> l2) {
        l1 = l2; //compilation error row #1
    }

    public void f3(List<?> c, List<S> l) {
        c = l; //ok row #2
        l = c; //compilation error row #3
    }
}

I really don't undersatand why row 2 is ok- if I transfer this method two lists, one is an object type list and one is a Strings one, I shoule get a compilation error? 我真的不小心,为什么第2行是好的 - 如果我将这个方法转移到两个列表,一个是对象类型列表,一个是字符串一个,我收到编译错误?

would really appriciate to understadn why each row should/shouldn't be compiled. 我真的很想知道为什么每行应该/不应该编译。

Why does this compile? 为什么编译?

List<?> c, List<S> l;
c = l; // OK

List<?> means (more or less) “list of something” (or more formally “list of unknown”), and a List<S> is one of those. List<?>表示(或多或少)“某事物列表”(或更正式的“未知列表”), List<S>就是其中之一。

—— -

Why does this not compile? 为什么这不编译?

List<Object> l1, List<?> l2;
l1 = l2; //compilation error

If it were allowed, you could then add anything (eg String) to l1 , but if l2 is anything other than List<Object> (eg Integer), you'd be putting the wrong type in l2 . 如果允许,则可以向l1添加任何内容(例如String),但如果l2不是List<Object> (例如Integer),则在l2输入错误的类型。 That's why this assignment is not allowed. 这就是为什么不允许这项任务的原因。

The other compilation error is more subtle, and also doesn't have a use case - that is, there's no reason to assign a typed list to an untyped one - but the wildcard ? 另一个编译错误更微妙,也没有用例 - 也就是说,没有理由将类型列表分配给无类型的 - 但是通配符? really means “unknown, but specific ”. 真的意思是“未知,但具体 ”。 This is not the same as “anything”. 这与“任何事情”都不一样。 It's “something”, but we don't know what. 这是“某事”,但我们不知道是什么。 Type S is something, but the compiler can't verify that it's the same something as S . 类型S是某种东西,但编译器无法验证它与S是否相同

Generics and wildcards are powerful because they ensure better typechecking during compile time, that's the main purpose of using them. 泛型和通配符是强大的,因为它们确保在编译期间更好的类型检查,这是使用它们的主要目的。 To make sure your code won't break at runtime due to poor type checking. 确保您的代码在运行时不会因类型检查不良而中断。

Source 资源

Although Integer is a subtype of Number, List<Integer> is not a subtype of List<Number> and, in fact, these two types are not related. 尽管Integer是Number的子类型,但List<Integer>不是List<Number>的子类型,实际上,这两种类型不相关。 The common parent of List<Number> and List<Integer> is List<?> . List<Number>List<Integer>的公共父是List<?>

In order to create a relationship between these classes so that the code can access Number 's methods through List<Integer> 's elements, use an upper bounded wildcard: 为了在这些类之间创建关系以便代码可以通过List<Integer>的元素访问Number的方法,请使用上限的通配符:

 List<? extends Integer> intList = new ArrayList<>(); List<? extends Number> numList = intList; // OK. List<? extends Integer> is a subtype of List<? extends Number> 

Because Integer is a subtype of Number , and numList is a list of Number objects, a relationship now exists between intList (a list of Integer objects) and numList . 因为IntegerNumber的子类型,而numListNumber对象的列表,所以intListInteger对象列表)和numList之间现在存在关系。 The following diagram shows the relationships between several List classes declared with both upper and lower bounded wildcards. 下图显示了使用上限和下限通配符声明的多个List类之间的关系。

To make use of subtyping and polymophism with wildcards you have to use bounded wildcards . 要使用通配符的子类型和多态性,必须使用有界通配符

public void f2(List<Object> l1, List<?> l2) {
  l1 = l2; //compilation error row #1
}

//correct way of doing it
public void f2(List<? extends Object> l3, List<?> l4) {
  l3 = l4; 
}

Compiler doesn't see l2 as a subtype of l1 编译器没有将l2视为l1的子类型

public void f3(List<?> c, List<S> l) {
  c = l; //ok row #2
  l = c; //compilation error row #3
}

Compiler doesn't see c as a subtype of l (rightly so, this could lead to runtime errors). 编译器没有将c视为l的子类型(正确地说,这可能导致运行时错误)。

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

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