Java:为什么Array.length没有(),而String.length()有()?

9
为什么获取数组的长度时不需要加括号,例如:
int [] ar;
System.out.println(ar.length); // no parentheses 

对于一个字符串而言,它将是

String st;
System.out.println(st.length());

我不同意这个问题和之前的问题相同,也不同意那个问题的答案回答了这个问题。之前的问题是“如何找到这些不同实体的长度?”而这个问题是“为什么获取字符串的长度需要括号,但获取数组的长度却不需要?”我担心答案可能是“你就是需要”,但无论如何,在其他问题的答案中都没有提到。 - Carl Manaster
我也不同意。这个问题涉及到字段访问和方法之间的区别。如果深入探讨,它还涉及到为什么Java API内部有不同的实现。 - dognose
4个回答

10
为什么Array.length没有(),但String.length()有?
在语法层面上,这实际上归结于“历史原因”和“Java(预)1.0语言设计者决定这样做”。只有真正了解“为什么”的语言设计者才能告诉你。
然而:
- length字段在数组对象的头部是特殊的,获取数组长度使用特殊的字节码。 - length字段不能通过任何手段改变,除非使用危险的本地代码黑客。这非常重要,以避免堆栈破坏等问题。(相比之下,即使是普通对象上的final字段也可以使用反射进行修改。) - 在这些方面,数组上的length确实不同于任何其他字段。
自(预)Java早期以来,API中的暴露字段已经过时。
大多数人会说这是一件好事。通过将长度信息公开为字符串、集合等类型的length()和size()方法,类库设计允许Java实现者更改相应类型的表示形式。如果直接公开字段,则在Java中无法实现此目的。

6
区别在于:
  • 数组的length(长度)不是关于实际内容的 - 它是维度!一个数组可以有length(长度)为10,但只包含2个元素。
  • 包含元素的对象(字符串是一个包含多个字符的对象)可能具有一定数量的对象。此计数可能会因添加或删除元素而变化。因此,length() 方法关于实际内容!

原因是数组是一种语言结构 - 因此,每当您想要了解有关数组的信息时(例如它的长度或其他),您必须从JVM检索一个固定值,而不是调用评估某些东西的方法。

Array 类只是实际 array 结构的代理。)


从技术上讲,array(小写 a)只是内存分配,用于在内存中存储 array.length 个元素。(这就是为什么更改维度时不能简单地调整大小,而总是需要创建一个新数组的原因 - 它需要在内存中重新定位(在 C 中称为 realloc),以便有足够的空间来存储 array.length * elementSize 位。)

另一方面,列表不关心其元素在内存中的实际位置,因此允许随时进行动态调整大小。 (所以它可以提供一个 size() 方法,因为它没有维度,并且只需要返回有关其内容的信息。)

为了更好地理解您的观点,我查阅了“语言契约”并找到了这个链接:https://dev59.com/Y2kw5IYBdhLWcg3wNX32,但仍然无法建立联系。您能否再添加1-2行关于您在此处使用的语言结构的说明? - C graphics

1
这是访问字段(无括号)和调用方法(需要括号,即使方法没有参数)之间的区别。
历史上,数组除了字段外,还可能有一个方法。字符串除了方法外,也可能有一个字段。字段更简单,这可能是为什么数组使用它的原因,但至少有两个原因说明String具有length方法是很好的:
  1. String实现了CharSequence接口,该接口定义了一个length()方法,因此String必须具有该方法。(除了静态常量外,接口不支持定义字段。)String可以将length作为一个方法和一个字段,但那会分散注意力。

  2. 灵活性。String的内部实现随着时间的推移而发生了变化:曾经它使用了一个内部char数组和单独的offsetlength字段来定义char数组中的一个区域。这样做是为了子字符串可以共享父字符串的char数组(具有不同的偏移量和长度),而不是复制数组。后来发现这种优化很少有益,所以现在,String只有一个正确大小的char数组,length方法读取数组的length字段。String不再具有自己的length字段,甚至没有私有的length字段,但如果它是类的公共API的一部分,他们不能删除它,这会减少对内部实现的实验的灵活性。


CharSequence是在Java 1.4中添加的,因此它并不是String具有length()方法的原因。 - Mark Rotteveel

0

数组的length是一个int字段,但String(和其他对象)通常使用getter方法。

请注意,两者之间的区别在于字符串的“length”仅仅是它在内部char数组中已经存储的信息量,而数组的length字段只是它的容量。


2
那么为什么?为什么一个对象没有公共字段,为什么数组没有一个简单的长度方法? - dognose
1
@dognose 长度是一个简单的 final 字段,可以被访问。由于数组的长度是不可变的,也就是说你不能动态地改变它的大小,因此公开该类的这个方面是可以的。 - Rogue
字符串是不可变的,因此容量和长度始终相同。 - Mark Rotteveel
@MarkRotteveel 在反射的眼中,不在同一層次。當然,你不能將 null 設置到 char 數組中,但如果你使用像 java.misc.Unsafe 這樣瘋狂的東西,在字符串上,特別是參考長度方法時就難說了。即使以那種形式,數組的長度也是不可設置的。 - Rogue

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