您的位置:首页 - 教程 - Java - 正文
java泛型的约束与局限性

内容来至java核心技术第9版第12章



1. 不能用基本类型参数化实例类型

         即,没有Pair<int>,Pair<float>等类型

2. 运行时类型检查只适用于原始类型,即JVM中不存在泛型或指定类型的泛型,导致无法进行某些判断

   ex.  if(a instanceof Pair<String>) ;  //--- error,无法判断a是Pair<String>的一个实例,因为运行时,类型擦出后变成pair<Object>,无法判断是否为String类型;

   同理,强制类型转换时也会出现同样的问题

   ex. Pair<String> p = (Pair<String>) a; //error, (Pair<String>) a运行时无法得知String类型,只能得到Pair<Object>,导致转换异常

   不同类型泛型擦出验证,以下代码说明JVM时是不区分泛型类型的,只保留原始类型

Pair<String> p1 = ...;

Pair<Integer> p2 = ...;

if(p1.getClass()==p2.getClass()); //true

3. 不能创建参数化类型的数组

pair<String> p = new Pair<Sting>[10]; //error

  因为擦出机制,运行时无法区分p的引用内容(泛型具体类型),导致出现"猫插入狗列表"等业务逻辑上的异常,因此java得设计者阻止了这种应用.
4. Varargs警告
  Varargs警告基于java不允许创建参数化类型数组,但是允许可变参数引用的情况(此时的参数为类型参数),以下理解为抑制ts数组的警告.

@SafeVarargs

Public static <T> void addAll(Collection<T> coll, T ... ts){ //ts理解为数组

for(t:ts)coll.add(t);

}

 
5. 不能实例化类型变量,new T(...), new T[...], T.class, JVM时变成new Object(...), new Object[...], Object.class,业务上不可能存在这样的调用,所有java阻止了这种应用.   但是通过引用传递的方式是可以到达某种类似效果的,比如:

Public static <T> pair<T> makePair(Class<T> cl){

try{

return new Pair<>(cl.newInstance,cl.newInstance);

}catch(Exception e){

return null;

}

}

...

Pair<String> p = Pair.makePair(String.class);

 
6. 禁止使用带有类型参数的静态域或方法,JVM时可能会遇到数据插入混乱问题,java阻止了这种应用.
7. 不能抛出或捕获泛型类的实例,甚至连扩展Throwable都是不允许的.

public class Problem<T> extends Exception{ //error, can't extends Throwable

...

}

public static <T extends Throwable> void doWork(Class<T> t){

try{

do Work;

}catch(T e){ //error, can't catch type variable

Logger.global.info(...)

}

}

//不过在异常规则允许下是可以用到类型参数的

 public static <T extends Throwable> void doWork()T t throw T //OK

{...}

 
8.注意擦出后的冲突,所以不能再泛型类中建立类似equals(T x)这样的方法,因为擦出后与Object.equals(object obj)冲突了(相同的方法参数与方法名).
 当两个接口是同一个接口的不同参数化时,要强行限制一个类或类型变量不能同时成为这两个类的子类,即不能同时extends或implements这两个接口(有可能与中间合成的桥方法冲突).

评论: