泛型类型注意细节:
1.泛型类型变量不能是基本数据类型
比如,没有ArrayList<double>,只有ArrayList<Double>。因为当类型擦除后,ArrayList的原始类型变为Object,但是Object类型不能存储double值,只能引用Double的值。
2.泛型类型没有特定的class
ArrayList<String> arrayList=new ArrayList<String>();
因为类型擦除之后,ArrayList<String>只剩下原始类型,泛型信息String不存在了。
那么,运行时进行类型查询的时候使用下面的方法是错误的
java限定了这种类型查询的方式
3.异常中使用泛型方式:
不能抛出也不能捕获泛型类的对象。事实上,泛型类扩展Throwable都不合法。如:下面的定义将不会通过编译:
public class Problem<T> extends Exception{......}
因为异常都是在运行时捕获和抛出的,而在编译的时候,泛型信息全都会被擦除掉。
不能再catch子句中使用泛型变量
4.不能声明参数化类型的数组。
Pair<String>[] table = newPair<String>(10); //ERROR
这是因为擦除后,table的类型变为Pair[],可以转化成一个Object[]。
Object[] objarray =table;
数组可以记住自己的元素类型,下面的赋值会抛出一个ArrayStoreException异常。
objarray ="Hello"; //ERROR
提示:如果需要收集参数化类型对象,直接使用ArrayList:ArrayList<Pair<String>>最安全且有效。
5.泛型类型的实例化
不能实例化泛型类型:
first = new T(); //ERROR
利用反射,调用Array.newInstance:
泛型在静态类和静态方法中的使用:
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数
举例说明:
因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。
但是要注意区分下面的一种情况:
因为这是一个泛型方法,在泛型方法中使用的T是自己在方法中定义的T,而不是泛型类中的T。
6.泛型规范说明提及另一个原则“要支持擦除的转换,需要强行制一个类或者类型变量不能同时成为两个接口的子类,而这两个子类是同一接品的不同参数化。”
class Calendar implements Comparable<Calendar>{ ... }
class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>{...} //ERROR
GregorianCalendar会实现Comparable<Calender>和Compable<GregorianCalendar>,这是同一个接口的不同参数化实现。
这一限制与类型擦除的关系并不很明确。非泛型版本:
class Calendar implements Comparable{ ... }
class GregorianCalendar extends Calendar implements Comparable{...} //ERROR
1.泛型类型变量不能是基本数据类型
比如,没有ArrayList<double>,只有ArrayList<Double>。因为当类型擦除后,ArrayList的原始类型变为Object,但是Object类型不能存储double值,只能引用Double的值。
2.泛型类型没有特定的class
ArrayList<String> arrayList=new ArrayList<String>();
因为类型擦除之后,ArrayList<String>只剩下原始类型,泛型信息String不存在了。
那么,运行时进行类型查询的时候使用下面的方法是错误的
if( arrayList instanceof ArrayList<String>)
java限定了这种类型查询的方式
if( arrayList instanceof ArrayList<?>)
? 是通配符的形式 ,将在后面一篇中介绍。
3.异常中使用泛型方式:
不能抛出也不能捕获泛型类的对象。事实上,泛型类扩展Throwable都不合法。如:下面的定义将不会通过编译:
public class Problem<T> extends Exception{......}
因为异常都是在运行时捕获和抛出的,而在编译的时候,泛型信息全都会被擦除掉。
不能再catch子句中使用泛型变量
4.不能声明参数化类型的数组。
Pair<String>[] table = newPair<String>(10); //ERROR
这是因为擦除后,table的类型变为Pair[],可以转化成一个Object[]。
Object[] objarray =table;
数组可以记住自己的元素类型,下面的赋值会抛出一个ArrayStoreException异常。
objarray ="Hello"; //ERROR
提示:如果需要收集参数化类型对象,直接使用ArrayList:ArrayList<Pair<String>>最安全且有效。
5.泛型类型的实例化
不能实例化泛型类型:
first = new T(); //ERROR
public<T> T[] minMax(T[] a){
T[] mm = new T[2]; //ERROR
...
}
利用反射,调用Array.newInstance:
publicstatic <T extends Comparable> T[]minmax(T[] a)
{
T[] mm == (T[])Array.newInstance(a.getClass().getComponentType(),2);
...
// 以替换掉以下代码
// Obeject[] mm = new Object[2];
// return (T[]) mm;
}
泛型在静态类和静态方法中的使用:
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数
举例说明:
public class Test2<T> {
public static T one; //编译错误
public static T show(T one){ //编译错误
return null;
}
}
因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。
但是要注意区分下面的一种情况:
public class Test2<T> {
public static <T >T show(T one){//这是正确的
return null;
}
}
因为这是一个泛型方法,在泛型方法中使用的T是自己在方法中定义的T,而不是泛型类中的T。
6.泛型规范说明提及另一个原则“要支持擦除的转换,需要强行制一个类或者类型变量不能同时成为两个接口的子类,而这两个子类是同一接品的不同参数化。”
class Calendar implements Comparable<Calendar>{ ... }
class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>{...} //ERROR
GregorianCalendar会实现Comparable<Calender>和Compable<GregorianCalendar>,这是同一个接口的不同参数化实现。
这一限制与类型擦除的关系并不很明确。非泛型版本:
class Calendar implements Comparable{ ... }
class GregorianCalendar extends Calendar implements Comparable{...} //ERROR