2011-12-06 118 views
2

此作品之间的区别:什么是对象数组和字符串数组

Object[] array = new Object[3]; 
array[0] = "ddd"; 
array[1] = new Integer(12); 

这并不:(新在整数崩溃)

Object[] array2 = new String[3]; 
array2[0] = "ddd"; 
array2[1] = new Integer(12); 

我读过有关covariance但仍无法理解第二个代码示例被禁止的基本技术原因,或者为什么抛出ArrayStoreException。 本质上,Object引用数组和String引用数组之间的区别是什么?

我明白,在第二个例子中,数组被实例化为向其添加字符串的意图,但是仍然有些东西不会在逻辑上点击。有人可以用简单的术语来解释它吗?

回答

1

让我做一个小的改变你的第二个例子来说明这是真的什么:

String[] array1 = new String[3]; 
Object[] array2 = array1; 
array2[0] = "ddd"; 
array2[1] = new Integer(12); // this one 

让我们假设标记声明的工作。 (它不......但让我们假设......)

现在如果我这样做会发生什么?

String wot = array1[1]; 

即赋值语句应该是静态类型安全,因为array1被声明为一个字符串数组。但它肯定不是动态类型安全的!简而言之,我们刚刚以一种非常基本的方式打破了Java静态输入。

Java避免这种破坏是通过将运行时类型检查作为标记语句的一部分,并且不允许将非字符串分配给String[]对象的元素。

+0

因此,禁止添加以防止其他问题(如ClassCastException)进一步受阻可能更好? – Sjoerd

+0

@Sjoerd - 是的。你能想象一下,如果执行一个静态类型安全的赋值或表达式会导致一个'ClassCastException',Java会是什么样子? –

3

Object引用可以容纳任何种类的Object,而String引用只能容纳String - 并且JVM将在运行时检查它。真的没有比这更多的东西了。

你的第二个例子实际上指出了Java语言设计中的一个缺陷。这种异常可能发生在运行时显然很糟糕!泛型特性的设计稍有不同,因此您不能在泛型集合中遇到同样的问题。 A String[] is-a Object[],遗憾地;但List<String>不是List<Object>

+0

是的,这在我看来是支持ArrayList而不是数组的主要原因之一 – Guillaume

1

在:

Object[] array2 = new String[3]; 

的类型参考Object[]的,但实际的对象,参考指的是的类型是String[]

当您尝试将一个Integer类型对象赋值给该数组时,引用被解引用并检查实际对象。在第二种情况下,数组对象的类型与正在插入的对象的类型不匹配。

这当然只能在运行时发现,因为编译器无法确切知道一旦程序执行时,array2将指向哪个对象(从技术上讲,它可能在这个微不足道的程序中,而不是一般情况下) 。

1

协方差的简单的定义:如果存在与类型参数集装箱<Ť>一个通用的容器类,X是T的子类,那么容器<X>是集装箱<Ť>的子类。

典型的例子是一个List。如果列表在Java中是固定的,那么列表<字符串>将是列表<对象>的子列表,因为字符串是Object的子类。但是在Java中,列表是而不是协变。数组协变。

协方差是一个有用的想法,但在某些情况下会导致问题。

String[] stringArray = new String[1]; 
Object[] objectArray = stringArray; 
objectArray[0] = new Integer(4); 
System.out.println("value=" + stringArray[0]); // what should this do? 

因为我们可以分配objectArray =字符串数组(因为它是协变),我们就可以分配给objectArray任何类型的对象的[0],这违反了你有当你声明一个字符串的“契约” []。这不能被编译器捕获。爪哇避免了这种情况的条件:

  1. 抛出ArrayStoreException信息时尝试分配不匹配的定义的类型的阵列(上述3行)
  2. 进行其它类不变的值。

数组是协变的,以便泛型允许排序和搜索被写入。见Arrays#sort()

Scala等语言允许程序员选择容器类是协变,逆变还是简单不变。