Java 数组是对象。它们继承自 Object 类。
JVM 规范没有规定对象的任何特定实现,只要它们的行为符合规范即可。在实践中,它是通过一个标头后跟对象的实际字段来实现的。
Java 中的数组不只是其原始组件的序列。它是一个对象,具有length 字段,并且具有方法。因此,与任何其他对象一样,它具有标头,然后是长度,然后是所有数组组件。
分配大小为零的数组是具有标头和大小但没有为实际组件分配空间的对象。
对数组的引用就像对任何其他对象的引用一样。 Java 中的数组与 C 中的数组不同,如果数组大小为零,则指向其开头的指针实际上是无效的。对数组的引用指向数组object,它的长度恰好为零并且没有实际项目。如果您尝试寻址此类数组中的任何元素,则不会出现有效指针问题。数组引用本身指向一个有效对象。然后,边界检查将显示任何索引超出范围,因此不会发生进一步的指针取消引用。
所以底线是对char[0] 的引用是对实际分配对象的有效引用。它根本没有超出长度的数据。
这与null 不同,null 是一个位全为零的引用,因此根本不指向任何地方。除了引用本身之外,没有分配任何内存,而对于char[0],为标头和长度分配了足够的内存。
对于字符串,两个空字符串不一定指向同一个字符数组。例如,如果你写:
String a = new String();
String b = new String();
你会得到两个不同的空字符串对象。它们中的每一个都有一个它指向的不同的空字符数组。这是因为String 类的无参数构造函数是这样实现的:
public String() {
this.value = new char[0];
}
您看到new 关键字的用法了吗?这意味着分配了一个新的数组对象,而不是从任何地方复制。
但请注意,如果您的来源是:
String a = "";
String b = "";
然后由于实习,它们将指向同一个字符串对象,因此指向同一个字符数组。另外,如果是:
String a = new String();
String b = new String(a);
然后你会有两个不同的String 对象,但它们都指向同一个内部字符数组。这是因为第二行的构造函数是:
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
同样,指向空字符串的指针肯定不同于空指针。它指向一个实际的字符串对象,该对象指向一个实际的字符数组对象。