为什么String.length()是一个方法?

如果一个String对象是不可变的(因此显然不能改变它的长度),为什么length()是一个方法,而不是简单地是public final int length例如在数组中?

它只是一个getter方法,还是进行某种计算?

试着看看这背后的逻辑。

Java是一种标准,而不仅仅是一种实现。 不同的供应商可以以不同的方式许可和实施Java,只要它们符合标准即可。 通过对字段进行标准调用,可以非常严重地限制实现,这是没有充分理由的。

对于类的未来而言,方法也更加灵活。 除了在一些非常早期的Java类中,几乎从未完成将最终常量公开为一个字段,该字段可以与类的每个实例具有不同的值,而不是作为方法。

length()方法早于 CharSequence接口,可能是它的第一个版本。 看看效果如何。 多年以后,没有任何向后兼容性的损失,CharSequence接口被引入并且非常适合。 对于一个领域来说这是不可能的。

因此,让我们真正颠倒这个问题(当你设计一个数十年来保持不变的类时,你应该做什么):这里的一个领域是什么,为什么不简单地把它变成一个方法呢?

也许.length()方法被认为与StringBuffer的相应方法更加一致,这显然需要多于final成员变量。

String类可能是为Java定义的最早的类之一。 有可能(这只是猜测)实现在final成员变量存在之前使用了.length()方法。 在将该方法的使用很好地嵌入到当时存在的Java代码体中之前,不需要很长时间。

也许是因为length()来自CharSequence接口 。 如果一个方法有多个实现,那么它是一个比变量更合理的抽象。

这是封装的基本原则。

封装的一部分是类应该从其接口隐藏它的实现(在“按合同设计”的接口意义上,而不是在Java关键字意义上)。

你想要的是字符串的长度 – 你不应该关心它是否被缓存,计算,委托给其他领域等。如果JDK人员希望改变实施方式,他们应该能够这样做你必须重新编译。

您应始终在公共类而不是公共字段中使用访问器方法,无论它们是否为final(请参阅Effective Java中的第14项)。

当您允许直接访问字段(即公开)时,您将失去封装的好处,这意味着您无法在不更改API的情况下更改表示(如果您这样做,则会破坏人员代码)并且您无法执行任何操作访问该字段时的操作。

有效的Java提供了一个非常好的经验法则:

如果类可以在其包外部访问,则提供访问器方法,以保持更改类的内部表示的灵活性。 如果公共类公开其数据字段,则所有改变其表示的希望都将丢失,因为客户端代码可以远程分发。

基本上,它是这样做的,因为这样做是很好的设计实践。 它留有空间在稍后阶段更改String的实现,而不会破坏每个人的代码。

String使用封装来隐藏其内部详细信息。 只要外部可见状态不变,不可变对象仍然可以自由地具有可变内部值。 长度可以懒惰计算。 我鼓励你看一下String的源代码。

在Open JDK中检查String的源代码,它只是一个getter。

但正如@SteveKuo指出的那样,这可能因实施而异。

在大多数当前的jvm实现中,Substring引用内容的原始String的char数组,并且它需要start和length字段来定义它们自己的内容,因此length()方法用作getter。 但是,这不是实现String的唯一可能方法。

在一个不同的可能实现中,每个String都可以拥有自己的char数组,并且由于char数组已经有一个长度正确的长度字段,因此String对象有一个冗余字段,因为String.length()是我们不知道的方法。必须这样做,只能引用内部array.length。

这是String的两种可能实现,它们都有自己的好的和坏的部分,并且它们可以互相替换,因为length()方法隐藏了存储长度的位置(内部数组或在自己的字段中)。