码迷,mamicode.com
首页 > 其他好文 > 详细

泛型(三)——约束与局限性

时间:2015-08-02 14:59:03      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:

  因为java虚拟机没有泛型这一说法,所以在使用java泛型时需要考虑一些限制,大多数限制都是由类型擦除引起的。

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

  不能用类型参数代替基本类型。因此,没有Pair<double>,只有Pair<Double>。当然其原因是类型擦除。擦除之后,Pair类含有Object类型的域,而Object不能存储double值。

2.运行时类型查询只适用于原始类型

  虚拟机中的对象总有一个特定的非泛型类型。因此,所有的类型查询只产生原始类型。例如:

Pair<String> pair = new Pair<String>();
if(pair instanceof Pair<String>)   //error
if(pair instanceof Pair<T>)  //error
if(pair instanceof Pair)  //true

那么同样的道理,getClass方法总是返回原始类型。例如:

Pair<String> a = new Pair<String>();
Pair<Integer> b = new Pair<Integer>();
System.out.println(a.getClass().equals(b.getClass()));  //输出true

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

  不能实例化参数化类型的数组,例如:

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

这有什么问题呢?擦除之后,pair的类型就变成了Pair[],这明显和我们的本意有区别,我们的本意是想根据不同的类型参数创建不同的表,所以java泛型直接限制不能创建。

4.不能实例化类型变量

  不能使用想new T(...),new T[...]或T.class这样的表达式中的类型变量,例如,下面的Pair<T>构造器就是非法的:

public Pair(){first = new T();}    //error

类型擦除将T改变成Object,而且我们本意肯定不希望调用new Object()。但是,可以通过反射调用Class.newInstance方法来构造泛型对象(在操作数据库时一般用这种方法封装不同的实体)。例如:

public static <T> Pair<T> makePair(Class<T> c1){
      try {
        return new Pair<>(c1.newInstance(),c1.newInstance());
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
        return null;
    }
}

同理,不能创建一个泛型数组:

public static <T> void minmax(T[] t){
    T[] mm = new T[2]; //error
}   

类型擦除会让这个方法永远构造Object[2]数组,同样我们可以通过反射调用Array.newInstance方法来构造泛型数组。(这样创建在什么地方用我还不知道,以前没用过)

public static <T> void minmax(T[] t){
    T[] mm = (T[]) Array.newInstance(t.getClass().getComponentType(), t.length);
}

5.泛型类的静态上下文中类型变量无效

public class Problem<T>{
    private static T first;  //error
    public static T getFirst(){}  //error
}

6.注意擦除后的冲突

  当泛型类型被擦除时,无法创建引发冲突的条件。下面是一个示例:

public class pair<T>{
    public void equals(T value);          
}

这个方法泛型擦除后变成public void equals(Object value),这个方法与Object.equals方法冲突。补救的方法只能重新命名。

7.不能抛出或捕获泛型类的实例

  既不能抛出也不能捕获泛型类对象。实际上,甚至泛型类扩展Throwable都是不合法的,例如以下定义就不能正常编译:

public class Problem<T> extends Exception{}  //error

catch子句不能使用类型变量,例如:以下方法将不能编译

public static <T extends Throwable> void doWork(){
    try {
    } catch (T e) { //error     
    }
}

不过在异常规范中使用类型变量是允许的,以下方法是合法的:

public static <T extends Throwable> void doWork(T t) throws T{
    try {
    } catch (Exception e) {
        throw t;
    }
}

 

参考资料:java核心技术 卷一

泛型(三)——约束与局限性

标签:

原文地址:http://www.cnblogs.com/duoluomengxing/p/4695679.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!