Länge und Länge () in Java

88

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

Gibt es einen Grund?

Nitish Upreti
quelle
3
Wurde bereits bei CodeRanch besprochen. Siehe die Diskussion hier.
fehlender Faktor

Antworten:

98

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

length- Arrays ( int[], double[], String[]) - kennen , um die Länge der Arrays

length()- String zugehöriges Objekt ( String, StringBuilderusw.) - die Länge der Schnur wissen

size()- Collection Object ( ArrayList, Setusw.) - die Größe der Sammlung kennen

Vergessen Sie jetzt, length()nur lengthund zu betrachten size().

lengthist keine Methode, daher ist es völlig sinnvoll, dass sie bei Objekten nicht funktioniert. Es funktioniert nur auf Arrays.
size()Sein Name beschreibt es besser und da es sich um eine Methode handelt, wird es für Objekte verwendet, die mit der Sammlung (Sammlungsframeworks) arbeiten, wie ich dort oben sagte.

Kommen wir nun zu length():
String ist kein primitives Array (also können wir es nicht verwenden .length) und auch keine Sammlung (also können wir es nicht verwenden .size()), deshalb brauchen wir auch ein anderes length()(behalte die Unterschiede und diene dem Zweck).

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

Saif
quelle
6
tolle Lösung!
Jeff Hu
27

Ein bisschen vereinfacht kann man sich Arrays als Sonderfall und nicht als gewöhnliche Klassen vorstellen (ein bisschen wie Primitive, aber nicht). String und alle Sammlungen sind Klassen, daher die Methoden zum Abrufen von Größe, Länge oder ähnlichen Dingen.

Ich denke, der Grund zum Zeitpunkt des Entwurfs war die Leistung. Wenn sie es heute erstellt haben, haben sie sich wahrscheinlich stattdessen so etwas wie Array-gestützte Sammlungsklassen ausgedacht.

Wenn jemand interessiert ist, hier 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());
  }
}

Wenn Sie den nicht so wichtigen Teil des Bytecodes, der javap -cin der Klasse ausgeführt wird, auf eine Weise abschneiden, erhalten Sie für die beiden letzten Zeilen Folgendes:

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 die JVM nur nach der Größe des Arrays (in JNI wäre dies ein Aufruf von GetArrayLength () gewesen), während im String-Fall (28-35) a ausgeführt werden muss Methodenaufruf, um die Länge zu erhalten.

Mitte der neunziger Jahre hätte es ohne gute JITs und ähnliches die Leistung völlig beeinträchtigt, nur den java.util.Vector (oder etwas Ähnliches) und kein Sprachkonstrukt zu haben, das sich nicht wirklich wie eine Klasse verhält, aber schnell ist. Sie hätten die Eigenschaft natürlich als Methodenaufruf maskieren und im Compiler behandeln können, aber ich denke, es wäre noch verwirrender gewesen, eine Methode für etwas zu haben, das keine echte Klasse ist.

Fredrik
quelle
1
Java behandelt Array als Objekte und Strings als unveränderliche Objekte !! : |
Nitish Upreti
@Myth: Ich verstehe Ihren Standpunkt nicht ... Die Länge-Eigenschaft von Arrays ist kein öffentliches Feld oder irgendetwas, es ist ein Konstrukt der JVM (Array-Länge ist sogar eine Operation im Bytecode). Es ist sehr offensichtlich, wenn Sie JNI ausführen oder wenn Sie nur den Code zerlegen, von dem er stammt.
Fredrik
Ich glaube nicht, dass die Begründung des ursprünglichen Designs nur die Leistung war. Wie würden Sie implementieren, Vectorwenn die Java-Sprache keine Array-Unterstützung hätte?
Holger
8

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

.length()ist eine Methode. Es wird verwendet, um die Länge von a zu ermitteln String. Der Wert wird nicht dupliziert.

Prabandha
quelle
8

Erwägen:

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

Es ist sehr wahrscheinlich, dass Strings und Arrays zu unterschiedlichen Zeiten entworfen wurden und daher unterschiedliche Konventionen verwendeten. Eine Rechtfertigung ist, dass, da Strings intern Arrays verwenden, eine Methode length()verwendet wurde, um die Verdoppelung derselben Informationen zu vermeiden. Ein weiterer Grund ist, dass die Verwendung einer Methode dazu length()beiträgt, die Unveränderlichkeit von Zeichenfolgen hervorzuheben, obwohl die Größe eines Arrays ebenfalls unveränderlich ist.

Letztendlich ist dies nur eine entstandene Inkonsistenz, die definitiv behoben werden würde, wenn die Sprache jemals von Grund auf neu gestaltet würde. Soweit ich weiß, machen keine anderen Sprachen (C #, Python, Scala usw.) dasselbe, daher ist dies wahrscheinlich nur ein kleiner Fehler, der als Teil der Sprache endete.

Sie erhalten eine Fehlermeldung, wenn Sie trotzdem die falsche verwenden.

Gordon Gustafson
quelle
Dies ist eine gerechtfertigtere und unvoreingenommenere Antwort.
Zubair Alam
3

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. Dies wird zu einem bestimmenden Attribut des Arrays. Unabhängig davon, was Sie mit einem Array der Länge N tun (Werte ändern, Nullen ändern usw.), handelt es sich immer um ein Array der Länge N.

Die Länge eines Strings ist zufällig; Es ist kein Attribut des Strings, sondern ein Nebenprodukt. Obwohl Java-Zeichenfolgen tatsächlich unveränderlich sind, können Sie ihre Länge ändern, wenn es möglich wäre, ihren Inhalt zu ändern. Das Abschalten des letzten Zeichens (wenn es möglich wäre) würde die Länge verringern.

Ich verstehe, dass dies eine feine Unterscheidung ist, und ich werde vielleicht dafür abgewählt, aber es ist wahr. Wenn ich ein Array mit der Länge 4 erstelle, ist diese Länge mit vier ein definierendes Merkmal des Arrays und gilt unabhängig davon, was darin enthalten ist. Wenn ich einen String mache, der "Hunde" enthält, hat dieser String die Länge 4, da er zufällig vier Zeichen enthält.

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

jakeboxer
quelle
2

Mir wurde beigebracht, dass bei Arrays die Länge aus folgenden Gründen nicht über eine Methode abgerufen wird: Programmierer würden die Länge nur einer lokalen Variablen zuweisen, bevor sie in eine Schleife eintreten (denken Sie an eine for-Schleife, bei der die Bedingung die Länge des Arrays verwendet). Der Programmierer würde dies angeblich tun, um Funktionsaufrufe zu reduzieren (und dadurch die Leistung zu verbessern). Das Problem ist, dass sich die Länge während der Schleife ändern könnte und die Variable nicht.

Matthew
quelle
10
Die Länge eines Arrays kann sich während der Schleife nicht ändern.
Fredrik
2
Sie können die Länge dieses bestimmten Arrays nicht ändern, aber Sie können derselben Variablen eine neue zuweisen
Bozho
2
@Bozho: Stimmt, aber dann ist es ein anderes Array, und wenn Sie dies absichtlich tun und nicht aktualisieren, was auch immer Sie in Ihrer Schleife überprüfen, haben Sie einen Fehler. Java hatte nie die Absicht, Sie davon abzuhalten, Fehler zu schreiben. Sie können Endlosschleifen, Rekursionen bis zu Ihrem Tod und alle Arten von logischen Fehlern ausführen, ohne dass Java versucht, Sie davon abzuhalten. Es ist ein guter Grund, die Länge nicht in einer Variablen zu speichern, aber es ist sicher nicht der Grund, warum sie so entworfen wurde.
Fredrik
1

Jedes Mal, wenn ein Array erstellt wird, wird seine Größe angegeben. Die Länge kann also als Konstruktionsattribut betrachtet werden. Für String ist es im Wesentlichen ein char-Array. Die Länge ist eine Eigenschaft des char-Arrays. Es ist nicht erforderlich, die Länge als Feld anzugeben, da nicht alles dieses Feld benötigt. http://www.programcreek.com/2013/11/start-from-length-length-in-java/

Ryan
quelle
0

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

Die Java-Sprachspezifikation in Abschnitt 4.3.1 besagt

Ein Objekt ist eine Klasseninstanz oder ein Array .

Array spielt also in Java in der Tat eine ganz besondere Rolle. Ich frage mich warum.

Man könnte argumentieren, dass das aktuelle Implementierungsarray für eine bessere Leistung wichtig ist / war. Aber dann ist es eine interne Struktur, die nicht freigelegt werden sollte.

Sie hätten die Eigenschaft natürlich als Methodenaufruf maskieren und im Compiler behandeln können, aber ich denke, es wäre noch verwirrender gewesen, eine Methode für etwas zu haben, das keine echte Klasse ist.

Ich stimme Fredrik zu, dass eine Optimierung des intelligenten Compilers 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 Zeichenfolgen und andere (unveränderliche) Auflistungstypen nicht gelöst haben, da z. B. stringauf einem charArray basiert, wie Sie in der Klassendefinition sehen können von String:

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

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

Als Ingenieur mag ich die Antwort "Weil es immer so war" wirklich nicht. und wünschte, es gäbe eine bessere Antwort. Aber in diesem Fall scheint es zu sein.

tl; dr

Meiner Meinung nach ist es ein Designfehler von Java und hätte nicht auf diese Weise implementiert werden sollen.

Michael Dorner
quelle