Länge und Länge () in Java

Warum haben wir die Länge eines Arrays als Attribut, array.length , und für String haben wir eine Methode, str.length() ?

Gibt es einen Grund?

Lassen Sie mich zuerst drei verschiedene Möglichkeiten für ähnliche Zwecke hervorheben.

lengtharrays ( int[] , double[] , String[] ) – um die Länge der Arrays zu kennen

length()String-bezogenes Objekt ( String , StringBuilder , etc) – um die Länge des StringBuilder zu kennen

size()Collection-Objekt ( ArrayList , Set , etc) – um die Größe der Collection zu kennen

Jetzt vergiss die length() betrachte nur length und size() .

length ist keine Methode, es macht also durchaus Sinn, dass es bei Objekten nicht funktioniert. Es funktioniert nur bei Arrays.
size() sein Name beschreibt es besser und wie es eine Methode ist, wird es im Falle der Objekte verwendet werden, die mit der Sammlung (Collection Frameworks) arbeiten, wie ich dort oben gesagt habe.

Kommen Sie nun auf length() :
String ist kein primitives Array (also können wir .length nicht verwenden) und auch keine Collection (daher können wir .size() ), deshalb brauchen wir auch ein anderes .size() , das length() (behalte die Unterschiede und diene dazu) die Absicht).

Als Antwort auf Warum?
Ich finde es nützlich, einfach zu merken und zu benutzen und freundlich.

Ein bisschen vereinfacht kann man sich vorstellen, dass Arrays ein Spezialfall sind und keine gewöhnlichen classn (ein bisschen wie Primitive, aber nicht). String und alle Sammlungen sind classn, daher die Methoden, um Größe, Länge oder ähnliches zu erhalten.

Ich denke, der Grund zur Zeit des Designs war die performance. Wenn sie es heute erstellt hätten, hätten sie wahrscheinlich eher etwas wie Array-gestützte Sammelklassen entwickelt.

Wenn jemand interessiert ist, hier ist ein kleiner Codeausschnitt, um den Unterschied zwischen den beiden im generierten Code zu veranschaulichen, zuerst die Quelle:

 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 den nicht so wichtigen Teil des Byte-Codes javap -c , führt das Ausführen von javap -c in der class für die beiden letzten Zeilen zu folgendem Ergebnis:

 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 

Im ersten Fall (20-25) fragt der Code nur die JVM nach der Größe des Arrays (in JNI wäre dies ein Aufruf von GetArrayLength ()) gewesen, während er im String-Fall (28-35) a benötigt Methodenaufruf, um die Länge zu erhalten.

In der Mitte der 90er Jahre, ohne gute JITs und so, hätte es die Performance total kaputt gemacht, nur den java.util.Vector (oder etwas Ähnliches) zu haben und kein Sprachkonstrukt, das sich nicht wirklich wie eine class benahm, sondern schnell war. Sie könnten natürlich die Eigenschaft als Methodenaufruf maskiert und im Compiler behandelt haben, aber ich denke, es wäre noch verwirrender gewesen, eine Methode für etwas zu haben, das keine echte class ist.

Erwägen:

 int[] myArray = new int[10]; String myString = "hello world!"; List myList = new ArrayList(); myArray.length // Gives the length of the array myString.length() // Gives the length of the string myList.size() // Gives the length of the list 

Es ist sehr wahrscheinlich, dass Strings und Arrays zu unterschiedlichen Zeiten entworfen wurden und daher unterschiedliche Konventionen verwenden. Eine Rechtfertigung besteht darin, dass, da Strings intern Arrays verwenden, eine Methode, length() , verwendet wurde, um eine Duplizierung derselben Information zu vermeiden. Eine andere ist, dass die Verwendung einer Methode length() die Unveränderlichkeit von Strings hervorhebt, obwohl die Größe eines Arrays ebenfalls nicht veränderbar ist.

Letztlich ist dies nur eine Widersprüchlichkeit, die entwickelt wurde, die definitiv behoben würde, wenn die Sprache von Grund auf neu gestaltet würde. Soweit ich weiß, tun keine anderen Sprachen (C #, Python, Scala, etc.) dasselbe, also ist dies wahrscheinlich nur ein kleiner Fehler, der als Teil der Sprache endete.

Sie erhalten einen Fehler, wenn Sie trotzdem den falschen Code verwenden.

.length ist eine einmalige Eigenschaft von Java. Es wird verwendet, um die Größe eines eindimensionalen Arrays zu finden .

.length() ist eine Methode. Es wird verwendet, um die Länge eines String . Es vermeidet, den Wert zu duplizieren.

In Java speichert ein Array seine Länge getrennt von der Struktur, die die Daten tatsächlich enthält. Wenn Sie ein Array erstellen, geben Sie dessen Länge an und dies wird zu einem definierenden Attribut des Arrays. Egal, was Sie mit einem Array der Länge N machen (Werte ändern, Null Dinge auslassen usw.), es wird immer ein Array der Länge N sein.

Die Länge einer Zeichenfolge ist zufällig; Es ist kein Attribut der Zeichenfolge, sondern ein Nebenprodukt. Obwohl Java Strings tatsächlich unveränderlich sind, könnten Sie ihre Länge ändern, wenn es möglich wäre, ihren Inhalt zu ändern. Wenn Sie das letzte Zeichen abknicken (wenn es möglich wäre), würde sich die Länge verringern.

Ich verstehe, dass dies eine feine Unterscheidung ist, und ich kann dafür abgelehnt werden, aber es ist wahr. Wenn ich ein Array der Länge 4 mache, ist diese Länge von vier ein definierendes Merkmal des Arrays und ist unabhängig davon wahr, was darin enthalten ist. Wenn ich einen String mache, der “Hunde” enthält, ist dieser String die Länge 4, weil er vier Zeichen enthält.

Ich sehe dies als Rechtfertigung dafür, eins mit einem Attribut und das andere mit einer Methode zu machen. In Wahrheit ist es vielleicht nur eine unbeabsichtigte Inkonsistenz, aber es hat immer Sinn für mich gemacht, und so habe ich immer darüber nachgedacht.

Mir wurde beigebracht, dass für Arrays die Länge aufgrund der folgenden Befürchtung nicht durch eine Methode abgerufen wird: Programmierer würden die Länge einer lokalen Variablen zuweisen, bevor sie in eine Schleife eintreten (denke an eine for-Schleife, bei der die Bedingung die Länge des Arrays verwendet) Dies würde angeblich dazu beitragen, functionsaufrufe zu reduzieren (und dadurch die performance zu verbessern.) Das Problem ist, dass sich die Länge während der Schleife ändern könnte und die Variable nicht.

Wenn ein Array erstellt wird, wird seine Größe angegeben. So kann die Länge als Konstruktionsattribut betrachtet werden. Für String ist es im Wesentlichen ein Char-Array. Length ist eine Eigenschaft des char-Arrays. Es gibt keine Notwendigkeit, Länge als Feld zu setzen, weil nicht alles dieses Feld benötigt. http://www.programcreek.com/2013/11/start-from-length-length-in-java/

Ich möchte nur einige Bemerkungen zu der großartigen Antwort von Fredrik hinzufügen.

Die Java-Sprachspezifikation in Abschnitt 4.3.1 besagt

Ein Objekt ist eine classninstanz oder ein Array .

So hat Array tatsächlich eine ganz besondere Rolle in Java. Ich wundere mich warum.

Man könnte argumentieren, dass das aktuelle Implementierungsarray wichtig für eine bessere performance ist. Aber als es eine interne Struktur ist, die nicht ausgesetzt werden sollte.

Sie könnten natürlich die Eigenschaft als Methodenaufruf maskiert und im Compiler behandelt haben, aber ich denke, es wäre noch verwirrender gewesen, eine Methode für etwas zu haben, das keine echte class ist.

Ich stimme Fredrik zu, dass eine intelligente Compiler-Optimierung die bessere Wahl gewesen wäre. Dies würde auch das Problem lösen, dass, selbst wenn Sie eine Eigenschaft für Arrays verwenden, Sie das Problem für Strings und andere (unveränderliche) Collection-Typen nicht getriggers haben, weil zB string auf einem char Array basiert, wie Sie auf der classndefinition von String :

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

Und ich stimme dem nicht zu, es wäre noch verwirrender, weil Array alle Methoden von java.lang.Object erbt.

Als Ingenieur mag ich die Antwort “Weil es immer so war”. und wünschte, es würde eine bessere Antwort geben. Aber in diesem Fall scheint es so zu sein.

tl; dr

Meiner Meinung nach ist es ein Designerrors von Java und hätte nicht so umgesetzt werden sollen.