不能用基本类型实例化类型参数
没有Pair<double>,只有Pair<Double>。原因是类型擦除,擦除之后,Pair类含有Object类型的域,而Object不能存储double值。这样做与java语言中基本类型的独立状态相一致。
Pair<LocalDate> pair=new DateInterval();
System.out.println(pair instanceof Pair);//true
Pair<String> p=new Pair<>();
System.out.println(p instanceof Pair);//true
Pair<String> stringPair = new Pair<>();
Pair<LocalDate> localPair = new Pair<>();
System.out.println(stringPair.getClass() == localPair.getClass());//true
试图查询一个对象是否属于某个泛型类型,只能测试是否是任意类型的Pair原始类型,if(pair instanceof Pair<LocalDate>)编译器会报错。 同理,getClass方法只是返回原始类型。所以不能用instanceof。
public class Singleton<T> {
private static T singInstance; //编译器报错
public static T getSingleInstance(){//编译器报错
if(singInstance==null){
singInstance=new T();//编译器报错
}
return singInstance;
}
}
不能在静态域或方法中引用类型变量。因为泛型是要在对象创建的时候才知道是什么类型的,而对象创建的代码执行先后顺序是static的部分,然后才是构造函数等等。所以在对象初始化之前static的部分已经执行了,如果你在静态部分引用的泛型,那么毫无疑问虚拟机根本不知道是什么东西,因为这个时候类还没有初始化。
泛型类对象不能扩展Throwable。
public class Problem<Pair> extends Exception{...}报错。
public class Problem extends Exception{...} 正确。
catch中不能使用类型变量,因为try时抛出的异常不一定是T指定的异常。
public class Problem{
public static <T extends Throwable> void doWork(T t){
try{
}catch (T e){//error
}
}
}
下面这种方法可以
public class Problem{
public static <T extends Throwable> void doWork(T t) throws T{//此时可以throws T
try{
}catch (Throwable e){//捕获到具体实例
t.initCause(e);
throw t;//这时候抛具体实例,所以throw t 和 throws T 是可以的!
}
}
}
ArrayList<T>[] intArr = new ArrayList<T>[10];参数化类型数组。
T[] intArr = new T[10]; 泛型数组。
ArrayList<Integer>[] intArr = new ArrayList<Integer>[10];//error
Object[] obj = intArr;
ArrayList<String> listStr = new ArrayList<>();
obj[0] = listStr;
//上面相当于使用数组移花接木,让编译器把ArrayList<Integer>当做了ArrayList<String>
ArrayList<Integer> listInt = intArr[0];
Integer data = listInt.get(0);//想要Integer,但却是String
假如允许泛型数组,第一行是正确的,那么类型擦除后,可以转换为Object[],然后向Object[]放ArrayList<String>,而不是我们要的ArrayList<Integer>。因为在运行时,类型是擦除的,运行时系统无法对数组中存储的类型做检查,系统只是看到像intArr数组里面放ArrayList对象。
Integer data = listInt.get(0)会被替换成Integer data =(Integer) listInt.get(0),但是data实际上指向ArrayList<String>,转为Integer,会报ClassCastException。
最后一行改为Object obj=listInt.get(0);它实际引用的是Integer类型,底层却是String类型,如果调用hashCode(),我们以为它执行的是Integer的hashCode,但它执行的是String的hashCode,那就很难发现错误。
如果能用泛型数组,就有一个矛盾的现象,泛型的出现就是为了消灭ClassCastException而出现,但是用泛型数组,它就可能引发ClassCastException,所以就不支持泛型数组。
声明类型为ArrayList<Integer>[]的变量是合法的,只是不能创建这些实例。
ArrayList<T>[] intArr = new ArrayList<T>[10];参数化类型数组。
T[] intArr = new T[10]; 泛型数组。 不能使用new T[10]来创建泛型数组。解决方案可以使用泛型数组包装器,比如ArrayList。
public static <T extends Comparable> T[] minmax(T... a){
T[] ts = (T[]) Array.newInstance(a.getClass().getComponentType(), 2);//创建长度为2的数组
ts[0]=a[0];
ts[1]=a[1];
ts[2]=a[2];****
return ts;
}
//调用
String[] minmax = minmax("a", "b", "c");
public Class<?> getComponentType()返回表示数组组件类型的Class,如果此类不表示数组,则此方法返回null。
不能使用像new T(),new T[],T.class这样的表达式中的类型变量。类型擦除后变成Object,本意肯定不希望调用new Object()。
要灵活创建泛型对象,最好的解决办法是提供一个构造器表达式。
public static <T> Pair<T> makePair(Class<T> cl){
Pair<T> tPair = null;
try {
tPair = new Pair<>(cl.newInstance(), cl.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return tPair;
}
//这个方法可以按照下列方式调用:
Pair<String> p = Pair.makePair(String.class);
不能使用T.class,这样是不合法的。Class类本身是泛型,比如String.class是一个Class<String>的实例,因此,makePair方法能够推断出pair类型。
public class Pair<T> {
public boolean equals(T value) {//error
return first.equals(value)&& second.equals(value);
}
}
Pair的equals方法报错。因为擦除后T变成Object,Pair的equals方法和Object的equals方法冲突,补救的方法就是Pair的equals改成其他名称。