Java核心技术知识点笔记—泛型程序设计(三)

前言:使用Java泛型时需要考虑一些限制。大多数限制是由类型擦除引起的。

1、约束与局限性

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

(2)运行时类型查询只适用于原始类型:虚拟机的对象总有一个特定的非泛型类型,因此,所有的类型查询只产生原始类型。

TestGenericC genericC = new TestGenericC<>();
if (genericC instanceof TestGenericC) //错误
if (genericC instanceof TestGenericC) //错误

TestGenericC genericC = new TestGenericC<>();
TestGenericC c = (TestGenericC)genericC;//警告:未检查的转换: 'TestGenericC' 转换为 'TestGenericC'

当试图使用instanceof查询一个对象是否属于某个泛型类型时,编译器将会报错;如果试图强制类型转换,则会得到一个警告。

(3)不能创建参数化类型的数组:

TestGenericC[] testGenericCS = new TestGenericC[1];

上述代码编译器会报错。问题在于,类型擦除后,testGenericCS的类型为TestGenericC[],可以转换为Object[]:

Object[] objects = testGenericCS;

通常,数组会记住它的元素类型,如果试图存储其他类型的元素,将会抛出一个ArrayStoreException的异常。但对于泛型类型,擦除会使这种机制无效,因此,在上例中,

objects[0] = 2;

能够通过检查,只是编译器会出现一个警告(将 'java.lang.Integer' 类型的元素存储到 'TestGenericC' 元素的数组将生成 'ArrayStoreException' )。出于这个原因,不允许创建参数化类型的数组。(注:可以声明通配符类型的数组再进行类型转换,如:

TestGenericC[] genericCS = (TestGenericC[]) new TestGenericC[10];

但似乎仍会出现一个警告(未检查的转换: 'TestGenericC[]' 转换为 'TestGenericC[]'))。

(4)Varargs警告:Java不支持泛型类型的数组,但对Varargs参数的规则却有所放松。如下例子:

    public  void test(T...ts){
        for (T t : ts) {
            System.out.print(t);
        }
    }

定义该方法编译器不会报错,但会得到一个警告(来自形参化 vararg 类型的可能的堆污染 )。事实上,为了调用这样的方法,Java虚拟机必须建立一个泛型数组,这正违反了(3)中的规则。

(5)不能实例化类型变量:不能使用想 new T(...),new T[...]或T.class这样的表达式中的类型变量。

(6)不能构造泛型数组

(7)泛型类的静态上下文中类型变量无效:不能在静态域或方法中引用类型变量。如:

public class TestGenericC {
    private static T instance; //错误
    public static T getInstance(){ //错误
        return instance;
    }
}

(8)不能抛出或捕获泛型类的实例:泛型类对象不能抛出或捕获。

(9)可以消除对受查异常的检查

(10)注意擦除后的冲突:当泛型类型擦除时,无法创建引发冲突的条件。

(11)要想支持擦除的转换,需要强行限制一个类或类型变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化。

你可能感兴趣的:(Java,java,泛型)