首先说一下问题:
java中不能创建泛型数组,否则会报错
应该如何使用?
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JavaGenericTypeTest {
/**
* 先说结论
* java泛型不支持数组
* 泛型和数组不能同时使用,
* 但是因为我们要创建数组,所以只能舍弃泛型,使用原生类型 raw type
* 即不带尖括号的类型
* 或者是使用原生类型创建数组后,强转为泛型类型
*
* 原因:
* 数组支持协变,而协变是错误的
*/
public void createGenericType(){
//创建list
List<Integer> list = new ArrayList<>();
//创建泛型 list数组 (去掉泛型,使具体化reifiable)第一种使用方式
//是因为原生类ArrayList不是泛型,所以它是"物化(reifiable)"的。
List<Integer>[] ll = new ArrayList[10];
ll[0] = new ArrayList<Integer>();
//方式2,类型更确定,也是创建泛型数组
List<Integer>[] ll2 = (List<Integer>[]) new ArrayList[10];
ll2[0] = new ArrayList<Integer>();
//创建泛型数组,会提示"泛型数组创建 generic array create"
// List<Integer> l = new ArrayList<Integer>[10];
}
//======================================================
public class A{
}
public void test(){
//强制转型原生类型数组
List<String>[] stringList = (ArrayList<String>[])new ArrayList[10];
Object[] objArray = new Object[10];
objArray = stringList;
objArray[0] = new ArrayList<Integer>(); // OPPS!!! 编译器不报错
}
public void test2(){
//强制转型原生类型数组,此处Object为原生类型
List<A>[] aList = (ArrayList<A>[])new ArrayList[10];
Object[] objArray = new Object[10];
objArray = aList;
objArray[0] = new ArrayList<Integer>(); // OPPS!!! 编译器不报错
}
public void test3(){
String[] a = new String[2];
Object[] b = a;
a[0] = "hi";
b[1] = Integer.valueOf(42);
}
// public void test4(){
// String[] a = (String[]) new Object[2];
// a[0] = "hi";
// a[1] = Integer.valueOf(42);
// }
// public void test5(){
// List<String> a = new ArrayList<>();
// List<Object> b = a;
// a[0] = "hi";
// b[1] = Integer.valueOf(42);
// }
// public void test6(){
// List<? extends String> d = new ArrayList<>();
// d.add("d");
// }
public void test7(){
//报错
/**
* ?通配符,不可以用于创建实例
*/
// List<?> l = new ArrayList<?>();
//不报错
List<Object> l2 = new ArrayList<Object>();
}
public void test8(List<?> l){
//只可以读,不可以添加,null除外
//报错
// l.add(1);
l.add(null);
}
public void test9(List<Object> l){
}
public void test10(){
test8(new ArrayList<String>());
}
public void test11(){
//报错
// test9(new ArrayList<String>());
}
/**
* super和extends 都限定了,只能存放A以及A的子类
* 只不过,
* (extends)一个不允许放(null除外),取出来为A以及Object(A的基类)
* (super)一个允许放入A以及A的子类,但是取出来必须是A的基类
* 允许放的,只能放A以及A的子类
* 关键点为,只可以为一种未知类型,如果该未知类型为A,那么只能是A,如果是B,只能是B,而不可以又是A,又是B,而Object就可以
*/
public void test12(){
List<? super A> l = new ArrayList<>();
l.add(new A());
List<? extends A> l2 = new ArrayList<>();
l2.add(null);
//报错
// l2.add(new A());
}
public void test13(){
Object[] strList = new String[10];
Object[] intList = new Integer[10];
intList[0] = 1;
Object[] x = strList; // 系统默认x为String类型数组
x[0] = intList[0]; // 运行报错
}
}
下面说一下原因:
根本原因为:java的数组协变是错误的(个人感觉),
比如:
Object[] o = new Object[5];
Integer[] i = new Integer[5];
o[0] = new A();
相当于Object[]类中有个方法add,该方法参数为Object,返回值为[Object,
即 [Object add(Object o)
Integer[]也类似
而程序语言的类型系统中,最主要是子类型关系,比如如何判断一个函数是另一个函数的子函数,我们都知道一个函数的参数为A,那么传入该函数的实例,必须是<:A(其中<:为类型系统中的子类型,详情看见https://en.wikipedia.org/w/index.php?search=subtype+system&title=Special%3ASearch&go=Go&ns0=1)
那根据子类型的公式
C <: A 并且 B <: D 那么 A ---> B <: C ---> D (其中--->代表函数,或者是一个操作,输入为A,输出为B)
如果c为a的子类型,并且b为d的子类型,那么函数a->b为c->d的子类型。
应用到数组中也是一样
Integer为Object的子类,[Integer为[Object的子类,
要想Object[]数组add方法为Integer[]的add方法的父类,那么应该为:
[Object add(Integer) 为 [Integer add(Object)方法的父类。
例如:
声音 f(狗)
汪汪 g(动物)
那么函数f为g的父类
参考资料: