如果一个String对象是不可变的(因此显然不能改变它的长度),为什么length()
是一个方法,而不是像public final int length
那样存在于数组中?
它只是一个getter方法,还是进行某种计算?
试着看看背后的逻辑。
答案 0 :(得分:19)
Java是一种标准,而不仅仅是一种实现。不同的供应商可以以不同的方式许可和实施Java,只要它们符合标准即可。通过对字段进行标准调用,可以非常严格地限制实现,这是没有充分理由的。
就类的未来而言,方法也更灵活。除了在一些非常早期的Java类中,几乎从未完成将最终常量公开为可以与类的每个实例具有不同值的字段,而不是作为方法。
length()
方法很好predates CharSequence接口,可能来自它的第一个版本。看看效果如何。多年以后,没有任何向后兼容性的损失,CharSequence接口被引入并且非常适合。对于一个字段,这是不可能的。
因此,让我们真正颠倒这个问题(当你设计一个几十年来保持不变的课程时,你应该做些什么):这里的一个领域有什么好处,为什么不简单地把它变成一个方法呢?
答案 1 :(得分:4)
或许.length()
方法被认为与StringBuffer
的相应方法更加一致,显然需要的不仅仅是final
成员变量。
String
类可能是为Java定义的最早的类之一。有可能(这只是猜测)实现在.length()
成员变量存在之前使用了final
方法。在将该方法的使用很好地嵌入到当时存在的Java代码体中之前,不需要很长时间。
答案 2 :(得分:3)
也许是因为length()来自CharSequence interface。如果一个方法有多个实现,那么它就是一个比变量更合理的抽象。
答案 3 :(得分:3)
这是封装的基本原则。
部分封装是类应该从其接口隐藏它的实现(在“按合同设计”的接口意义上,而不是在Java关键字意义上)。
你想要的是字符串的长度 - 你不应该在意它是否被缓存,计算,委托给其他领域等等。如果JDK人员希望改变实施方式,他们应该能够这样做,无需重新编译。
答案 4 :(得分:3)
您应该始终在公共类而不是公共字段中使用访问器方法,无论它们是否为final(请参阅Effective Java中的第14项)。
当您允许直接访问字段(即公开)时,您将失去封装的好处,这意味着您无需更改API即可更改表示(如果您这样做,则会破坏人员代码)在访问该字段时无法执行任何操作。
Effective Java 提供了一个非常好的经验法则:
如果一个类可以在其包之外访问,则提供访问器方法,以保持更改类的内部表示的灵活性。如果公共类公开其数据字段,那么改变其表示的所有希望都将丢失,因为客户端代码可以远程分发。
基本上,它是以这种方式完成的,因为这样做是很好的设计实践。它留有余地在稍后阶段改变String
的实现,而不会破坏每个人的代码。
答案 5 :(得分:2)
String正在使用封装来隐藏其内部详细信息。只要外部可见状态不变,不可变对象仍然可以自由地具有可变内部值。长度可以懒惰计算。我鼓励你看一下String的源代码。
答案 6 :(得分:1)
答案 7 :(得分:1)
在大多数当前的jvm实现中,Substring引用内容的原始String的char数组,它需要start和length字段来定义自己的内容,因此length()方法用作getter。但是,这不是实现String的唯一可能方法。
在另一种可能的实现中,每个String都可以有自己的char数组,因为char数组已经有一个长度正确的长度字段,所以对于String对象有一个冗余字段,因为String.length()
是一个方法我们不必这样做,只能引用内部array.length。
这是String的两种可能的实现,它们都有自己的好的和坏的部分,并且它们可以互相替换,因为length()方法隐藏了存储长度的位置(内部数组或在自己的字段中)。