图 破坏类型安全引起的错误 二义性错误
GenMap在声明是使用了个类型参数T和V 因此在创建GenMap的对象的时候也需要提供个具体的类类型来替代这个类型参数 例如
清单 多个参数的范型类
GenMap gm = new GenMap();
GenMap gm = new GenMap();
上例中T和V虽然看起来是两个不同的类型参数但是在使用这个范型类的时候 T和V很有可能被替换成同一种类型因此在声明多个类型参数的范型类时 要注意避免这种二义性错误例如
清单二义性错误
public class GenMap {
//编译错误 二义性错误
public void set(T t){}
public void set(V v){}
}
在上面这段代码如果T和V被替换成同一种类型set函数的签名(signature)就是完全一样的 所以编译器会报告二义性错误正确的用法是声明个不同名的方法 例如
清单 二义性错误
public class GenMap {
public void setKey(T t){}
public void setValue(V v){}
}
图 二义性错误 使用通配符
前面我们创建了范型的列表如果我需要一个方法来处理范型列表例如 我们希望把列表中的每个元素都打印出来但是类型参数(type parameter)只能使用在声明一个范型类的时候如果类型参数使用在函数定义里会导致编译错误
public static void print(GenList list){}//编译错误
在这种情况下 我们需要用另外一种方法来表示一个范型类 否则 就可能需要书写多个print函数
public static void print(GenList list){}
public static void print(GenList list){}
…
public static void print(GenList list){}
JSE 中提供了范型的通配符??可以用来代替任何类型 例如使用通配符来实现print方法
public static void print(GenList list) {}
范型的一些局限型
() 类型参数不能实例化 例如
T t= new T(); //编译错误
() 不能实例化类型参数的数组
T[] ts= new T[]; //编译错误
() 类的静态变量不能声明为类型参数类型
public class GenClass {
private static T t;//编译错误
}
() 范型类不能继承自Throwable以及其子类
public GenExpection extends Exception{}//编译错误
范型小结
范型是JSE 所提供的一项强大的功能 使用范型可以创建类型安全的可重用的代码 虽然目前Java的范型还无法和C++的范型相提并论 但是 随着Java语言本事的演进 范型会在Java语言中发挥更大的作用的