java泛型理解

泛型得弄清楚下面这些的区别

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.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值