java泛型使用时的约束与局限性

来源:互联网 发布:windows vista开不了机 编辑:程序博客网 时间:2024/05/21 06:13

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

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

java
if(a intanceof Pair<Stirng>) //ERROR

java
Pair<String> p = (Pair<String>) a; //Error

上面的2个例子在java中都是错误的
+ 类型查询只适用于原始类型
+ 参数化类型不能进行强制类型转换

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

    Pair<String>[] table = new Pair<String>[10];

在这只是不允许创建这个数组,但声明这个变量还是合法的

@Varargs警告

向参数个数可变的方法传递一个泛型类型的数组

    public sttic <T> void addAll(Conllection<T> coll,T... TS){        for (t :ts){            coll.add(t);        }    }

下面是调用的状况

    Collection<Pair<String>> talbe = ...;    Pair<String> pair1 = ...;    Pair<String> pair2 = ...;    addAll(table,pair1,pair2);

要调用这个方法的话,java虚拟机就必需建立一个Pair 数组,这就违反了规定,不过对于这种状况,规则有所放松,你只会得到一个警告
解决警告的方法有2中
1. 在包含addAll调用的方法增加标注@SuppessWarnings(“unchecked”)
2. 如果是java SE7 中可以直接在addAll上标注@SafeVarargs
java
@SafeVarargs
public static <T> void addAll(Collection<T> coll,T... ts)

不能实例化类型变量

不能使用new T(…) ,new T[…] 或者T。class这样的表达式中的类型就那个变量,下面的构造器方法就是错误的

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

在这里类型擦除后T 将变成Object,而且本意不希望调用 new Object().但是可以通过反射调用Class.newInstance方法来构造泛型对象
+ 错误的调用方法

    first = T.class.newInstance(); //ERROR
  • 正确的调用方法
    1. 新建一个方法
    public static <T> Pair<T> makePair(Class<T> cl){        try{            return new Pair<>(cl.newInstance(),cl.newInstance());        }catch(Excepiton ex){            return null;        }    }
2. 调用
    Pair<String> p = Pair.makePair(String.clss);

Class本身就是泛型,而String.class是一个Class的一个实例,因此makePair能够推导出pair的类型

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

不能在静态域或方法中引用类型变量

    private static T singleTnstance; //ERROR    public static T getSingleInstance(){ //ERROR        if(singleInstance == null){            return singleInstance;        }    }

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

既不能抛出也不能捕获泛型类对象.甚至泛型类型扩展Thtowable都是不合法的

    public class Problem<T> extends Exception {/***/} //ERROR -- can't extend Thtowable

catch子居中不能使用类型变量如下面这个例子

    public static <T extends Throwbale> void doWork(Class<T> t){        try{            do work        }catch(T e){            Logger.global.info(...)        }    }

但是在异常规范中使用类型变量是允许的.以下方法是合法的

    public static <T extends Throwable> void doWork(T t) throws T{        try{            do work        }catch(Throwable realCause){            t.initCause(realCause)            throw t;        }    }

注意泛型擦除后的冲突

看下面这个例子

    public class Pair<T>{        public boolean equals(T t){            return first.equals(value) && second.equals(value);        }    }

从概念上讲他有2个方法
boolean equals(String) //泛型的方法
boolean equals(Object) //Object超类的方法

这里类型擦除后我们认为就是
boolean equals(Object)
但是这里的会与Object类的equals冲突

泛型还有一个规则
要想支持类型擦除的转换,就需要强制限制一个类或类型变量不能同时成为两个接口类型的子类而这两个接口是同一接口的不同参数化

错误的例子

    class Calendar implements Comparable<Calendar>{...}    class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>{...}

GregorianCalendar 会实现Comparable 和 Comparable
而这就是同一接口的不同参数化

原创粉丝点击