length and length() in Java
为什么我们将数组的长度作为属性
有什么原因吗?
让我首先强调三种用于类似目的的不同方式。
现在忘了
现在进入
字符串不是原始数组(因此我们不能使用
作为为什么的答案?
我发现它很有用,易于记忆,易于使用且友好。
稍微简化一下,您可以认为它是一种特殊情况,而不是普通类(有点像基元,但不是)。字符串和所有集合都是类,因此获取大小,长度或类似内容的方法。
我猜设计的原因是性能。如果他们今天创建了它,他们可能想出了一些类似数组支持的集合类。
如果有人感兴趣,下面是一小段代码,以说明所生成代码中两者之间的区别,首先是源代码:
1 2 3 4 5 6 7 8 |
截断字节码中不太重要的部分,在类上运行
1 2 3 4 5 6 7 8 | 20: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 23: aload_1 24: arraylength 25: invokevirtual #4; //Method java/io/PrintStream.println:(I)V 28: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 31: aload_2 32: invokevirtual #5; //Method java/lang/String.length:()I 35: invokevirtual #4; //Method java/io/PrintStream.println:(I)V |
在第一种情况下(20-25),代码仅向JVM请求数组的大小(在JNI中,这将是对GetArrayLength()的调用),而在String情况下(28-35),它需要执行以下操作:方法调用以获取长度。
在1990年代中期,如果没有良好的JIT和功能,仅使用java.util.Vector(或类似的东西),而不是像一个类却表现得并不快的语言构造,将完全丧失性能。他们当然可以将属性掩盖为方法调用并在编译器中进行处理,但是我认为在不是真正类的东西上使用方法会更加令人困惑。
考虑:
1 2 3 4 5 6 7 | int[] myArray = new int[10]; String myString ="hello world!"; List<int> myList = new ArrayList<int>(); myArray.length // Gives the length of the array myString.length() // Gives the length of the string myList.size() // Gives the length of the list |
字符串和数组很可能是在不同的时间设计的,因此最终使用了不同的约定。一种理由是,由于字符串内部使用数组,因此使用了
最终,这只是演变而来的不一致,如果从头开始重新设计该语言,那肯定会得到解决。据我所知,没有其他语言(C#,Python,Scala等)做同样的事情,因此这可能只是作为该语言一部分而出现的轻微缺陷。
如果仍然使用错误的代码,则会出现错误。
在Java中,数组的长度与实际保存数据的结构分开存储。创建数组时,可以指定其长度,该长度将成为数组的定义属性。无论您对长度为N的数组执行任何操作(更改值,清空内容等),它将始终是长度为N的数组。
字符串的长度是偶然的。它不是字符串的属性,而是副产品。尽管Java字符串实际上是不可变的,但是如果可以更改其内容,则可以更改其长度。剔除最后一个字符(如果可能)将缩短长度。
我知道这是一个很好的区别,我可能会对此表示反对,但这是事实。如果我制作一个长度为4的数组,则该长度为4是该数组的定义特征,并且无论包含什么内容,它都是正确的。如果我创建一个包含" dogs"的字符串,则该字符串的长度为4,因为它恰好包含四个字符。
我认为这是对一个属性进行处理而另一个对方法进行处理的理由。实际上,这可能只是无意间的不一致,但这对我来说总是有意义的,这就是我一直在思考的方式。
有人告诉我,对于数组,由于以下担心,无法通过方法检索长度:程序员在进入循环之前只会将长度分配给局部变量(想想for循环,其中条件语句使用数组的长度。)程序员据说这样做可以减少对函数的调用(从而提高性能)。问题是长度可能会在循环过程中更改,而变量不会更改。
每当创建数组时,都会指定其大小。因此,长度可以视为构造属性。对于String,它本质上是一个char数组。长度是char数组的属性。不需要将长度作为字段,因为并非所有内容都需要该字段。
我只想对弗雷德里克的精彩回答加一些评论。
第4.3.1节中的Java语言规范指出
An object is a class instance or an array.
因此,数组在Java中确实扮演着非常特殊的角色。我不知道为什么。
有人可能会争辩说,当前的实现数组对于提高性能非常重要。但是比起它,它是一个内部结构,不应暴露出来。
They could of course have masked the property as a method call and handled it in the compiler but I think it would have been even more confusing to have a method on something that isn't a real class.
我同意Fredrik的观点,即明智的编译器优化将是更好的选择。这也将解决问题,即使您对数组使用属性,也无法解决字符串和其他(不可变)集合类型的问题,因为例如,
1 2 | public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; // ... |
而且我不同意这样做会更加令人困惑,因为array确实从
作为一名工程师,我真的不喜欢"因为一直都是这样"的答案。希望会有更好的答案。但是在这种情况下似乎是这样。
tl; dr
在我看来,这是Java的设计缺陷,不应以这种方式实现。