java泛型理解

来源:互联网 发布:qt模型视图知乎 编辑:程序博客网 时间:2024/06/13 13:36
泛型得弄清楚下面这些的区别

1,List
2,List<Object>
3,List<Number>
4,List<?>
5,List<? extends Number>
6,List<? super Long>

普通的泛型使用估计没啥问题,但是带上 ? 的泛型就会变得很复杂。

对于 <? super T> 和 <? extends T> 看看这个例子:

如果要将某一个数组中的元素拷贝至另一个的话

1,先看看这个方法签名:
Java code
?
1
public static <T> void copy(List<T> src, List<T> dest)


如果 src 和 dest 是相同泛型参数的话,这个签名是没有问题,但是由于泛型类与数组不一样,由于泛型类并不具有协变性,也就是说下面的代码是错误的:
Java code
?
1
List<Object> objs = new ArrayList<Long>();


数组是协变性的,下面的代码是正确的:
Java code
?
1
Object[] objs = new Long[4];


用这个 copy 方法的话,如果 src 是 List<Long>,而 dest 是 List<Object> 的话,这样就会产生编译错误。但是实际上 List<Long> 中的每一个元素是可以赋值给 List<Object> 的,因此这个 copy 方法签名还有待完善。

由于泛型类不具有协变性,但是 Java 的泛型提供了一个通配符类型 ? 使用这个可以将泛型类变成协变的,下面的代码是正确的:
Java code
?
1
 List<? extends Object> objs = new ArrayList<Long>();


<? extends Object> 表示泛型是 Object 或者是 Object 的子类型,同理
<? super Long> 表示泛型是 Long 或者是 Long 的父类型。

这样就可以把 copy 方法完善成为:
 
Java code
?
1
public static <T> void copy (List<? extends T> src, List<? super T> dest)


至于其他的,看看下面的语句哪些正确的,哪些是不正确的?

Pair 是个泛型类,SubTypeOfPair 是 Pair 的子类

Java code
?
1
2
3
4
5
Collection<Pair<String, Long>> c1 = new ArrayList<Pair<String, Long>>();
 
Collection<Pair<String, Long>> c2 = c1;            // s1
Collection<Pair<String, ?>> c3 = c1;               // s2
Collection<? extends Pair<String, ?>> c4 = c1;     // s3


Java code
?
1
2
3
4
5
6
Collection<SubTypeOfPair<String, Long>> c1 = new ArrayList<SubTypeOfPair<String, Long>>();
 
Collection<Pair<String, Long>> c2 = c1;            // s4
Collection<SubTypeOfPair<String, Long>> c3 = c1;   // s5
Collection<Pair<String, ?>> c4 = c1;               // s6
Collection<? extends Pair<String, ?>> c5 = c1;     // s7



I will try to explain the Java generics using two simple rules. These rules suffice to answer your question and are basically enough to remember for almost any case:

  1. Two generic types X<A> and X<B> are never assignable unless A = B. I.e., generics areinvariant by default.
  2. Wildcards allow the assignment of X<A>:
    • to X<?>
    • to X<? extends T> iff A is assignable to T (apply rules recursively to A and T)
    • to X<? super T> iff T is assignable to A (apply rules recursively to T and A)

Case c3 = c1

In your example, you try to assign Collection<Pair<String,Long>> to Collection<Pair<String,?>>. That is, in your case A = Pair<String,Long> and B = Pair<String,?>. Since these types are not equal, they are not assignable; they violate Rule 1.

The question is, why doesn't the wildcard help? The answer is simple:
Rule 2 is NOT transitive. I.e., X<X<A>> cannot be assinged to X<X<?>>, there has to be a wildcard in the outermost level; otherwise Rule 2 does not apply to the outermost level.

Case c4 = c1

Here, you got a wildcard in the outer type. Because it is in the outer type, Rule 2 kicks in: A = Pair<String,?> is assignable to B = ? extends Pair<String,Long> (again, because of Rule 2). Therefore, this is legal.

General approach

Here is how you can check any complex generic type: Simply check each generic level by level using the two rules. Start with the outermost level. Once a level violates a rules, you know the assignment is illegal; if all levels adhere to the rules, then the assignment is legal. Lets consider your types again:

X = Collection<Pair<String,Long>>Y = Collection<Pair<String,?>>Z = Collection<? extends Pair<String,?>> 

Is X assignable to Y ?

// Outermost level:A = Pair<String,Long>, B = Pair<String,?>  => B is no wildcard and A != B (Rule 1), so this is illegal!

Is X assignable to Z ?

// Outermost level:A = Pair<String,Long>, B = ? extends Pair<String,?>  => We got a wildcard, so Rule 2 states this is legal if the inner level is legal// Inner level: (we have to check both parameters)A = String, B = String => Equal, Rule 1 applies, fine!A = Long, B = ? => B is wildcard, Rule 2 applies, fine!

Simple Rule to Remember

Each level of generic nesting either needs to be completely identical (A=B) or B needs to contain a wildcard in this level.


0 0
原创粉丝点击