泛型不能万能的,有些事情,泛型真做不了。

泛型类型能不能实例化?

1
T test = new T(); // ERROR

因为在 Java 编译期没法确定泛型参数化类型,也就找不到对应的类字节码文件,所以自然就不行了。

此外由于T 被擦除为 Object,如果可以 new T() 则就变成了 new Object(),失去了本意。

泛型数组

泛型数组相关的申明:

1
2
3
4
5
6
List<String>[] list11 = new ArrayList<String>[10]; //编译错误,非法创建 
List<String>[] list12 = new ArrayList<?>[10]; //编译错误,需要强转类型
List<String>[] list13 = (List<String>[]) new ArrayList<?>[10]; //OK,但是会有警告
List<?>[] list14 = new ArrayList<String>[10]; //编译错误,非法创建
List<?>[] list15 = new ArrayList<?>[10]; //OK
List<String>[] list6 = new ArrayList[10]; //OK,但是会有警告

因为在 Java 中是不能创建一个确切的泛型类型的数组的,除非是采用通配符的方式且要做显式类型转换才可以。

需要说明的是, 只是不允许创建这些数组, 而声明类型为 ArrayList<String>[] 的变量仍是合法的。不过不能用 new ArrayList<String>[10] 初始化这个变量。

因为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Pair<String>[] pairs = new Pair<String>[10];
//擦除之后
Pair[] pairs = new Pair[10];
/*
数组会记住他的元素类型。这是一个安全措施。对于这样的数组,将他转换为Object[]。
*/
Pair[] pairs = new Pair[10];
Object[] objects = pairs;
objects[0] = "123";
/*
编译器不会报错,但数组会记住他的元素类型,运行后会报ArrayStoreException.
pairs会记得他是Pair数组,但他并不记得自己是Pair<String>数组还是Pair<Interger>数组
如果我们在Pair<String>数组中放入Pair<Interget>是不会得到ArrayStoreException异常,但这是不安全的。因此参数化类型的数组是完全禁止的。
*/

讨巧的使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class GenericsDemo30{  
public static void main(String args[]){
Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组
fun2(i) ;
}
public static <T> T[] fun1(T...arg){ // 接收可变参数
return arg ; // 返回泛型数组
}
public static <T> void fun2(T param[]){ // 输出
System.out.print("接收泛型数组:") ;
for(T t:param){
System.out.print(t + "、") ;
}
}
}

如何实例化一个泛型类和泛型数组

如果我们确实需要实例化一个泛型,应该如何做呢?反射!

1
2
3
4
5
6
7
8
9
10
class Main{
static <T> T newTclass (Class < T > clazz) throws InstantiationException, IllegalAccessException {
T obj = clazz.newInstance();
return obj;
}

public static void main(String[] args) throws IllegalAccessException, InstantiationException {
String s = newTclass(String.class);//实例化一个泛型
}
}

那我们如何实例化泛型数组呢?还是反射!

我们可以通过使用 java.lang.reflect.Array.newInstance(Class<T> componentType, int length) 方法来创建一个具有指定类型和维度的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ArrayWithTypeToken<T> {
private T[] array;

public ArrayWithTypeToken(Class<T> type, int size) {
array = (T[]) Array.newInstance(type, size);
}

public void put(int index, T item) {
array[index] = item;
}

public T get(int index) {
return array[index];
}

public T[] create() {
return array;
}
}


class Main{
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
ArrayWithTypeToken<Integer> arrayToken = new ArrayWithTypeToken<Integer>(Integer.class, 100);
Integer[] array = arrayToken.create();//实例化一个泛型数组
}
}

如何理解泛型类中的静态方法和静态变量?

泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数

1
2
3
4
5
6
public class Test2<T> {    
public static T one; //编译错误
public static T show(T one){ //编译错误
return null;
}
}

因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。

对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。

但注意区分以下情况:

1
2
3
4
5
6
public class Test2<T> {    

public static <T >T show(T one){ //这是正确的
return null;
}
}

因为这是一个泛型方法,在泛型方法中使用的T是自己在方法中定义的 T,而不是泛型类中的T。

__END__