Java数组是同质的,但ArrayList不是,这是什么意思?

17
如果我们有一个Type[],那么我们只能在其中存储Type或其子类型。ArrayList也是如此。那么为什么说一个是同质的而另一个不是呢?

5
谁告诉你ArrayList不是同种类型的?只要你不绕过泛型,它们就和数组一样同种类型。(如果你绕过泛型,那么你应该将其与Object[]进行比较。) - user2357112
任何数组的每个元素都必须是相同的原始类型或相同的引用类型。ArrayList的每个元素都必须是相同的引用类型。 - Peter Lawrey
2个回答

27

数组在添加元素时会对元素类型进行运行时检查。也就是说,如果添加的新元素类型不同,则会在运行时抛出一个ArrayStoreException异常。这就是为什么数组被认为是“同质”的原因。

对于ArrayList(以及通用的List),则不是这样。由于在运行时发生类型擦除,它实际上可以容纳任何对象。

以下代码在运行时会抛出异常:

Object[] array = new String[3];
array[0] = "a";
array[1] = 1;   // throws java.lang.ArrayStoreException

与下面代码不同,下面的代码虽然编译和运行没有问题(尽管编译器会警告因为它没有正确使用泛型):

ArrayList list = new ArrayList<String>();
list.add("a");
list.add(1);    // OK
list.add(new Object());  // OK

通过正确使用泛型,即将变量list声明为类型ArrayList<String>而不是ArrayList,问题在编译时被避免:

ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add(1);  // compilation error
list.add(new Object());  // compilation error

即使有一个泛型声明的列表,你也可以在运行时避免异常发生:

ArrayList<String> list = new ArrayList<String>();
list.add("a");
Method[] methods = List.class.getMethods();
for(Method m : methods) {
    if(m.getName().equals("add")) {
        m.invoke(list, 1);
        break;
    }
}
System.out.println(list.get(0));
System.out.println((Object) list.get(1));

输出结果:

a

1


你能否在答案中嵌入“绕过泛型”并展示使用泛型确实是同质的吗? - totoro
以下代码可以编译并运行,但在编译时可能会收到警告。 - Powerlord
感谢您的发布,它在JDK8中成功运行,但在17中却不行。我得到了“main”线程中的异常java.lang.IllegalArgumentException: wrong number of arguments at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at com.example.demo.DemoApplication.main(DemoApplication.java:17) - prostý člověk

3
是的。Java数组是同质的,因为当你在Java中声明任何数组时,你必须声明它的类型。 例如:
int arr[]; //type is int
    String arr[]; //type is String
    float arr[]; //type is float

现在,如果您尝试将任何其他数据类型存储在声明的数组中,它将是编译时错误。 例如:

 int arr=new int[5];
     arr[0]="I am a String not int"; //compile time error

但是 ArrayListCollection 的一部分,它们保存的是 Object,而不是任何特定的 data-type [如果我们不谈论 generics],并且因为 Java 中的每个东西都直接或间接继承自 Object 类,所以它不会给你 compile-time error,类型检查将在 run-time 上进行。

例如:

 ArrayList al=new ArrayList();//type is Object
    al.add("I am a String");  //Bacause String class in inherited from Object Class
    al.add(1);//the int 1 will first autobox into Integer class then stored in al ArrayList.Now bacause Integer class is also inherited from Object class,it will*/ allow you to store
    al.add(UserDefinedClass); //because every User defined class is also inherited from Object class,so it will also allow you.

现在你是否注意到,我们没有定义 ArrayList al 的任何数据类型,但仍然存储了不同类型的值:这就是为什么 ArrayList 存储 Object 而不是特定数据类型的原因,因此它们是异构的而不是同构的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接