【问题标题】:length and length() in JavaJava中的长度和长度()
【发布时间】:2010-12-30 05:54:18
【问题描述】:

为什么我们有一个数组的长度作为属性array.length,而对于String我们有一个方法str.length()

有什么原因吗?

【问题讨论】:

  • 之前已经在 CodeRanch 讨论过。见讨论here.

标签: java arrays string


【解决方案1】:

稍微简化一下,您可以将其视为数组是一种特殊情况,而不是普通的类(有点像原语,但不是)。字符串和所有集合都是类,因此有获取大小、长度或类似内容的方法。

我猜当时设计的原因是性能。如果他们今天创建它,他们可能会想出类似数组支持的集合类之类的东西。

如果有人有兴趣,这里有一个小sn-p的代码来说明两者在生成代码中的区别,首先是源码:

public class LengthTest {
  public static void main(String[] args) {
    int[] array = {12,1,4};
    String string = "Hoo";
    System.out.println(array.length);
    System.out.println(string.length());
  }
}

削减字节码中不那么重要的部分,在类上运行javap -c,最后两行结果如下:

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(或类似的东西)而不是一种行为并不像类但实际上是快速地。他们当然可以将属性作为方法调用进行掩码并在编译器中处理它,但我认为在不是真正类的东西上使用方法会更加混乱。

【讨论】:

  • Java 将数组视为对象,将字符串视为不可变对象! :|
  • @Myth:我不明白你的意思......数组的长度属性不是公共字段或任何东西,它是jvm的构造(arraylength甚至是字节码中的操作)。当你做 JNI 或者你只是反汇编它来自的代码时,这是非常明显的。
  • 我不认为最初设计的原因仅仅是性能。当 Java 语言不支持数组时,你将如何实现 Vector
【解决方案2】:

考虑:

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

字符串和数组很可能是在不同的时间设计的,因此最终使用了不同的约定。一个理由是,由于字符串在内部使用数组,因此使用了length() 方法来避免重复相同的信息。另一个是使用length() 方法有助于强调字符串的不变性,即使数组的大小也是不变的。

归根结底,这只是一种不断演变的不一致,如果从头开始重新设计语言,肯定会解决这个问题。据我所知,没有其他语言(C#、Python、Scala 等)做同样的事情,所以这很可能只是语言中的一个小缺陷。

如果你用错了,你会得到一个错误。

【讨论】:

  • 这是更合理和公正的答案。
【解决方案3】:

我只是想通过Fredrik 为伟大的answer 补充一些意见。

Java Language Specification in Section 4.3.1 状态

一个对象是一个类实例或一个数组

所以数组在Java中确实有着非常特殊的作用。我很想知道为什么。

有人可能会争辩说,当前的实现数组对于更好的性能很重要。但它是一个内部结构,不应该暴露。

他们当然可以将属性伪装成方法调用并在编译器中处理它,但我认为在不是真实类的东西上使用方法会更加混乱。

我同意 Fredrik 的观点,智能编译器优化会是更好的选择。这也可以解决问题,即使您使用数组的属性,您也没有解决字符串和其他(不可变)集合类型的问题,因为例如,string 是基于 char 数组,因为可以在String的类定义上看到:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {           
    private final char value[]; // ...

我不同意这会更令人困惑,因为数组确实继承了all methods from java.lang.Object

作为一名工程师,我真的不喜欢“因为一直都是这样”的答案。并希望有更好的答案。但在这种情况下,它似乎是。

tl;dr

在我看来,这是Java的设计缺陷,不应该这样实现。

【讨论】:

    【解决方案4】:

    .length 是 Java 的一次性属性。它用于查找一维数组的大小。

    .length() 是一种方法。它用于查找 String 的长度。它避免了重复值。

    【讨论】:

      【解决方案5】:

      让我首先强调实现类似目的的三种不同方式。

      length -- 数组 (int[], double[], String[]) -- 知道数组的长度

      length() -- String相关对象 (String, StringBuilder, etc) -- 知道String的长度

      size() -- Collection Object (ArrayList, Set, etc) -- 知道Collection的大小

      现在忘记length(),只考虑lengthsize()

      length 不是一种方法,因此它不适用于对象是完全有道理的。它只适用于数组。
      size() 它的名字更好地描述了它,因为它是一种方法,它将用于那些使用集合(集合框架)的对象,正如我在上面所说的那样。

      现在就来length()
      字符串不是原始数组(所以我们不能使用.length)也不是集合(所以我们不能使用.size())这就是为什么我们还需要一个不同的数组length()(保持差异并提供服务目的)。

      回答为什么?
      我觉得它很有用,易于记忆和使用,而且友好。

      【讨论】:

      • 很棒的解决方案!
      【解决方案6】:

      每当创建数组时,都会指定其大小。所以长度可以被认为是一个构造属性。对于 String,它本质上是一个 char 数组。长度是 char 数组的一个属性。没有必要把长度作为一个字段,因为不是所有的东西都需要这个字段。 http://www.programcreek.com/2013/11/start-from-length-length-in-java/

      【讨论】:

        【解决方案7】:

        我被告知对于数组,由于以下恐惧,不会通过方法检索长度:程序员只会在进入循环之前将长度分配给局部变量(想想条件使用数组长度的 for 循环。 ) 程序员应该这样做是为了减少函数调用(从而提高性能)。问题是在循环期间长度可能会改变,而变量不会改变。

        【讨论】:

        • 循环中数组的长度不能改变。
        • 你不能改变这个特定数组的长度,但是你可以给同一个变量分配一个新的
        • @Bozho:是的,但它是另一个数组,如果你故意这样做并且不更新你检查循环的任何内容,你就有一个错误。 Java 从来没有打算阻止您编写错误。你可以做无限循环、递归直到你死和各种逻辑错误,而java不会试图阻止你。不将长度存储在变量中是一个很好的理由,但它肯定不是这样设计的原因。
        【解决方案8】:

        在 Java 中,Array 将其长度与实际保存数据的结构分开存储。创建数组时,您指定其长度,这将成为数组的定义属性。无论你对一个长度为 N 的数组做什么(改变值、空出东西等),它始终是一个长度为 N 的数组。

        字符串的长度是偶然的;它不是字符串的属性,而是副产品。尽管 Java 字符串实际上是不可变的,但如果可以更改它们的内容,则可以更改它们的长度。敲掉最后一个字符(如果可能的话)会缩短长度。

        我知道这是一个很好的区别,我可能会因此而被否决,但这是真的。如果我制作一个长度为 4 的数组,则该长度为 4 是该数组的定义特征,并且无论其中包含什么都是正确的。如果我创建一个包含“dogs”的字符串,则该字符串的长度为 4,因为它恰好包含四个字符。

        我认为这是用一个属性做一个,另一个用一个方法做的理由。事实上,这可能只是一种无意的不一致,但对我来说总是有意义的,而且我一直是这样想的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-14
          • 2018-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多