零长度数组如何在内存中表示?

Jim*_*Jim 6 java arrays string char native-code

Java原始对象映射到本机基元.
所以我的问题是如何char value[] = new char[0];表现?
它是否依赖于gcc编译器实现(本机代码)?这是否意味着所有空Java都String指向同一个地址?

tha*_*guy 8

内存布局未定义,因为它是一个实现细节.

以下是IBM如何为其64位JVM 描述数组的内存布局:

  1. 64位用于类指针(即信令char)
  2. 标志的64位(例如,说这个对象是一个数组)
  3. 锁定数据的64位(用于同步)
  4. 数组长度为64位(仅使用32位,但字段是边界对齐的)
  5. 数据为0位,因为数组没有元素

这总共是256位或32个字节.

在Java中,a String和a char[]不是一回事.A String将是一个包含对a的引用的单独对象char[].

  • @Jim答案试图用比特级详细解释.有什么东西不清楚吗? (2认同)

Rea*_*tic 7

Java数组是对象.他们从Object班上继承.

JVM规范没有规定对象的任何特定实现,前提是它们的行为符合规范.在实践中,它使用标题后跟对象的实际字段来实现.

Java中的数组是不是只是其基本组成部分的序列.它是一个对象,它有length字段,它有方法.因此,与任何其他对象一样,它具有标题,后跟长度,后跟所有数组组件.

分配大小为零的数组是具有标题和大小但没有为实际组件分配空间的对象.

对数组的引用就像对任何其他对象的引用一样.Java中的数组与C中的数组不同,如果数组的大小为零,则指向其开头的指针实际上是无效的.对数组的引用指向数组对象,该对象恰好具有零长度而没有实际项目.如果您尝试解决此类数组中的任何元素,则不会出现有效指针的问题.数组引用本身指向有效对象.然后,边界检查将显示任何超出范围的索引,因此不会再进行指针解除引用.

所以底线是对a的引用char[0]是对实际分配对象的有效引用.它没有超出长度的数据.

这不同于null一个参考,其位全部为零,因此根本不指向任何地方.除了引用本身之外没有分配任何内存,而为char[0]头部和长度分配了足够的内存.


至于字符串,两个空字符串不一定指向相同的字符数组.例如,如果你写:

String a = new String();
String b = new String();
Run Code Online (Sandbox Code Playgroud)

你会得到两个不同的空字符串对象.它们中的每一个都有一个与之指向的明显的空字符数组.这是因为类的no-args构造函数String实现如下:

public String() {
    this.value = new char[0];
}
Run Code Online (Sandbox Code Playgroud)

你看到new关键字的使用?这意味着分配了一个新的数组对象,而不是从任何地方复制.

但请注意,如果您的来源是:

String a = "";
String b = "";
Run Code Online (Sandbox Code Playgroud)

然后由于实习,它们将指向相同的字符串对象,因此指向相同的字符数组.另外,如果它是:

String a = new String();
String b = new String(a);
Run Code Online (Sandbox Code Playgroud)

然后你会有两个不同的String对象,但它们都会指向相同的内部字符数组.这是因为第二行的构造函数是:

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}
Run Code Online (Sandbox Code Playgroud)

同样,指向空字符串的指针肯定与空指针不同.它指向一个实际的字符串对象,它指向一个实际的字符数组对象.


Lou*_*man 5

创建的两个不同对象在引用相等性方面new 必须是不同的,所以不,它们不是同一个对象.

另外,String对常量字符串""的任何两个Java 引用都将引用同一个对象,因为编译时常量字符串会被实现.