600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > java泛型程序设计——Varargs 警告+不能实例化类型变量

java泛型程序设计——Varargs 警告+不能实例化类型变量

时间:2018-12-22 14:05:12

相关推荐

java泛型程序设计——Varargs 警告+不能实例化类型变量

【0】README

0.1)本文描述+源代码均 转自 core java volume 1, 旨在理解 java泛型程序设计 的Varargs 警告+不能实例化类型变量的知识;

【1】 Varargs 警告

1.1)一个相关问题:向参数个数可变的方法传递一个泛型类型的实例;

1.1.1)考虑以下方法, 它的参数个数是可变的:

public static<T> void addAll(Collection<T) coll, T...ts){......}

1.1.2)应该记得, 实际上参数ts 是一个数组, 包含所有实参, 考虑以下调用:

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

1.1.3)为了调用上述方法:java 虚拟机必须建立一个 Pair 数组, 这就违反了前面的规则, 不过, 对于这种case , 你只会得到一个警告, 而不是 错误;

1.4)可以采用以下两种方法来抑制这种警告(Methods):(解决方法)

M1)一种方法是 为 包含 addAll 调用的方法增加 标注

@SuppressWarnings("unchecked");

M2)在java se 7中, 还可以用 @SafeVarargs 直接标注addAll 方法:

@SafeVarargspublic static <T> void addAll(Collection<T> coll, T...ts);

现在就可以用 泛型类型来调用这个方法了;

Annotation)

A1)可以使用 @SafeVarargs 标注来消除创建泛型数组的有关限制, 方法如下:

@SafeVarargsstatic <E> E[] array(E... array){return array;}

A2)现在可以调用:

Pair<String>[] table = array(pair1, pair2);

这看起来方便, 不过隐藏着危险, 如下代码:

Object[] objarray = table;objarray[0] = new Pair<Employee>();

能顺利运行而不会出现 ArrayStoreException 异常 (因为数组存储只会检查擦除的类型), 但在处理 table[0] 时 你会在别处得到一个异常;

【2】不能实例化类型变量

2.1)不能使用像 new T(…), new T[…] 或 T.class 这样的表达式中的类型变量。

2.1.1)看个荔枝:(下面的 Pair 构造器就是非法的)

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

2.1.2)类型擦除将T 改变成 Object, 而且, 本意肯定不希望调用 new Object()。2.1.3)但是可以通过反射调用 Class.newInstance 方法来构造泛型对象:

然而,我们却不能调用: first = T.class.newInstance();//ERROR

2.1.4)因为, 表达式 T.class是不合法的, 必须像下面这样设计 API 以便可以支配Class 对象:

public static<T> Pair<T> makePair(Class<T> cl){try{ return new Pair<>(c1.newInstance(), c1.newInstance()) }catch(Exception ex) {return null;}}

2.1.5)以上方法可以按照下列方式调用:

Pair<String>p = Pair.makePair(String.class);

Attention)Class 类本身就是泛型, 如, String.class 是一个class《String》的实例(事实上, 它是唯一的实例)。 因此, makePair 方法能够推断出 pair 的类型;2.1.6) 不能构造一个 泛型数组:

public static <T extends Comparable> T[] minmax(T[] a) { T[] mm = new T[2]; ...} //ERROR

类型擦除会让这个方法永远构造 Object[2]数组;

2.2)如果数组仅仅是作为一个类的私有实例域, 就可以将这个数组声明为 Object[], 并且在获取元素时进行类型转换。

2.2.1)看个荔枝: 如 ArrayLIst 可以这样实现:

public class ArrayList<E>{private Object[] elements;...@SuppressWarnings("unchecked")public E get(int n){return (E) elements[n]; //获取元素时进行类型转换}pubic void set(int n, E e){elements[n] =e;}}

2.2.2)实际的实现没有这么清晰:

public class ArrayList<E>{paivate E[] elements;...public ArrayList(){ elements = (E[])new Object[0]; }}

2.2.3)这里, 强制类型转换 E[] 是一个假想, 而类型 擦除使其无法察觉;

2.3)由于 minmax方法 返回 T[] 数组, 使得这一技术无法施展, 如果掩盖这个类型会有运行时错误。假设实现代码:

public static <T extends Comparable> T[] minmax(T...a){Object[] mm = new Object[2];...reutrn (T[]) mm;}

2.4)调用String[] ss = minmax(“tom”, “dick”, “Harry”);

对上述代码的分析(Analysis):

A1)编译时不会有任何警告。但Object[] 引用赋给 String[] 变量时, 将会发生 ClassCastException 异常;A2)在这种case下, 利用反射,调用 Array.newIntance;

public static <T extemds Comparable> T[] minmax(T... a){T[] mm = (T[])mm.newInstance(a.getClass().getComponentType(), 2);}

A3)ArrayList 类的toArray方法就没有这么幸运了。它需要生成一个 T[] 数组, 但没有成分类类型。因此, 有下面两种不同的形式:

Object[] toArray();T[] toArray(T[] result);

第二个方法接收一个数组参数。如果数组足够大, 就是用这个数组。 否则, 用result 的成分类型构造一个足够大的 新数组;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。