Strings sind Objekte in Java. Warum verwenden wir sie nicht mit 'new'?


104

Normalerweise erstellen wir Objekte mit dem newSchlüsselwort:

Object obj = new Object();

Strings sind Objekte, aber wir verwenden sie nicht new, um sie zu erstellen:

String str = "Hello World";

Warum ist das? Kann ich mit einen String machen new?



1
Weil String-Literale bereits Objekte sind.
Marquis von Lorne

1
Beachten Sie, dass new String(...)dies verwendet wurde, um ein Implementierungsdetail zu umgehen, wenn große Zeichenfolgen mit Teilzeichenfolgen versehen werden. Dies wurde in Java 7 behoben und ist nicht mehr erforderlich.
Thorbjørn Ravn Andersen

Ich bin der 100. Liker dieses Beitrags. :)
Mukit09

Antworten:


130

Zusätzlich zu dem, was bereits gesagt wurde, werden String- Literale (dh Strings wie, "abcd"aber nicht wie new String("abcd")) in Java interniert. Dies bedeutet, dass Sie jedes Mal, wenn Sie auf "abcd" verweisen, einen Verweis auf eine einzelne StringInstanz anstatt auf eine neue erhalten jedes Mal. So haben Sie:

String a = "abcd";
String b = "abcd";

a == b; //True

aber wenn du hättest

String a = new String("abcd");
String b = new String("abcd");

dann ist es möglich zu haben

a == b; // False

(und falls jemand daran erinnert werden muss, verwenden Sie immer .equals()zum Vergleichen von Strings; ==Tests für die physische Gleichheit).

Das Internieren von String-Literalen ist gut, da sie häufig mehrmals verwendet werden. Betrachten Sie zum Beispiel den (erfundenen) Code:

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

Wenn wir keine Internierung von Strings hätten, müsste "Nächste Iteration" zehnmal instanziiert werden, während sie jetzt nur noch einmal instanziiert wird.


1
Wenn Sie String a = new String ("abcd") verwenden, bedeutet dies, dass zwei Zeichenfolgen mit ähnlichem Inhalt im Speicher vorhanden sind.
geändert

1
Richtig - der Compiler wird nicht unbedingt prüfen, ob ein solcher String bereits interniert wurde (obwohl Sie sicherlich einen schreiben könnten, der dies getan hat).
Danben

Ja, diese Optimierung ist möglich, da Zeichenfolgen unveränderlich sind und daher problemlos gemeinsam genutzt werden können. Die gemeinsame "asdf" -Handhabung ist eine Implementierung des Entwurfsmusters "Flyweight".
Manuel Aldana

Niemand sagte, dass es nicht möglich ist, nur dass es nicht garantiert ist. War das deine Ablehnung?
Danben

Was meinst du mit "== Tests für Objektgleichheit"? Das scheint mir nicht wahr zu sein, aber vielleicht haben Sie etwas anderes gemeint als das, was dies zu bedeuten scheint.
Dawood ibn Kareem

32

Strings sind "spezielle" Objekte in Java. Die Java-Designer haben mit Bedacht entschieden, dass Strings so oft verwendet werden, dass sie ihre eigene Syntax sowie eine Caching-Strategie benötigen. Wenn Sie eine Zeichenfolge deklarieren, indem Sie sagen:

String myString = "something";

myString ist eine Referenz auf ein String-Objekt mit dem Wert "etwas". Wenn Sie später erklären:

String myOtherString = "something";

Java ist intelligent genug, um herauszufinden, dass myString und myOtherString identisch sind, und speichert sie in einer globalen String-Tabelle als dasselbe Objekt. Dies hängt davon ab, dass Sie Strings nicht ändern können, um dies zu tun. Dies verringert den Speicherbedarf und kann Vergleiche beschleunigen.

Wenn Sie stattdessen schreiben

String myOtherString = new String("something");

Java erstellt für Sie ein brandneues Objekt, das sich vom myString-Objekt unterscheidet.


Hey ... es erfordert keine "unendliche Weisheit", um die Notwendigkeit einer syntaktischen Unterstützung für String-Literale zu erkennen. Nahezu jedes andere ernsthafte Programmiersprachen-Design unterstützt eine Art String-Literal.
Stephen C


16
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

Hoffe das klärt ein paar Zweifel. :) :)


String d = neuer String ("def"); // 1 Objekt + "def" wird zum Pool hinzugefügt -> hier wird "def" nur dann zum Pool hinzugefügt, wenn es noch nicht vorhanden ist
Soututherton

@southerton Sinnlos. Es ist schon im Pool. Es wurde dort vom Compiler platziert.
Marquis von Lorne

@EJP warum (e == d) ist hier falsch? beide beziehen sich auf dasselbe Objekt "def" im Pool, oder?
Raja

String c = neuer String ("abc"); // 1 Objekt ... ist diese Aussage korrekt? Wenn "abc" bereits aus dem Konstantenpool referenziert wurde, wozu dient dann die Methode inter?
Prashanth Debbadwar

6

Es ist eine Abkürzung. Es war ursprünglich nicht so, aber Java hat es geändert.

Diese FAQ spricht kurz darüber. Das Java Specification Guide spricht auch darüber. Aber ich kann es online nicht finden.


2
Defekter Link, und mir sind keine weiteren Beweise dafür bekannt, dass er jemals geändert wurde.
Marquis von Lorne

1
@EJP Es ist immer noch in der Wayback-Maschine, wenn das nützlich ist.
Arjan

6

Der String unterliegt einigen Optimierungen (mangels eines besseren Ausdrucks). Beachten Sie, dass String im Gegensatz zu anderen Objekten auch eine Operatorüberladung aufweist (für den Operator +). Es ist also ein Sonderfall.


1
Das + ist eigentlich ein Operator, der in einen StringBuilder.append (..) -Aufruf übersetzt wird.
Whiskysierra

5

Wir verwenden normalerweise String-Literale, um unnötige Objekte zu vermeiden. Wenn wir zum Erstellen eines String-Objekts einen neuen Operator verwenden, wird jedes Mal ein neues Objekt erstellt.

Beispiel:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

Für den obigen Code im Speicher:

Geben Sie hier die Bildbeschreibung ein


2

In Java sind Strings ein Sonderfall mit vielen Regeln, die nur für Strings gelten. Die doppelten Anführungszeichen bewirken, dass der Compiler ein String-Objekt erstellt. Da String-Objekte unveränderlich sind, kann der Compiler mehrere Strings internieren und einen größeren String-Pool erstellen. Zwei identische String-Konstanten haben immer dieselbe Objektreferenz. Wenn dies nicht der Fall sein soll, können Sie einen neuen String ("") verwenden. Dadurch wird zur Laufzeit ein String-Objekt erstellt. Die intern () -Methode war früher üblich, damit dynamisch erstellte Zeichenfolgen mit der Zeichenfolgen-Nachschlagetabelle verglichen werden. Sobald eine Zeichenfolge interniert ist, zeigt die Objektreferenz auf die kanonische Zeichenfolgeninstanz.

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

Wenn der Klassenlader eine Klasse lädt, werden alle String-Konstanten zum String-Pool hinzugefügt.


"Die doppelten Anführungszeichen bewirken, dass der Compiler ein String-Objekt erstellt." unterbewerteter Kommentar
csguy

0

Syntethischer Zucker. Das

String s = new String("ABC");

Die Syntax ist weiterhin verfügbar.


1
Das ist nicht ganz richtig. s = neuer String ("ABC") liefert nicht die gleichen Ergebnisse wie s = "ABC". Siehe Danbens Kommentar.
Steve B.

2
Ironischerweise wird zuerst eine String-Instanz erstellt, die "ABC" inline darstellt - und diese dann als Argument an den Konstruktoraufruf übergeben, der einen String mit identischem Wert zurückgibt.
Andrzej Doyle

1
Der gültige Anwendungsfall für diesen Konstruktor ist String small = new String(huge.substring(int, int));, mit dem Sie den großen Basiswert char[]aus dem ursprünglichen hugeString recyceln können .
Pascal Thivent

1
@PascalThivent ja, aber nicht mehr mit Java 8. Es werden keine Arrays mehr gemeinsam genutzt (in Vorbereitung auf andere Optimierungen wie die automatische Deduplizierung von Zeichenfolgen mit G1 oder die bevorstehende Zeichenfolgenkomprimierung).
eckes

@AndrzejDoyle Nicht korrekt. Der Compiler erstellt das Objekt für das Literal.
Marquis von Lorne

0

Sie können weiterhin new String("string")Zeichenfolgen verwenden , aber es wäre schwieriger, neue Zeichenfolgen ohne Zeichenfolgenliterale zu erstellen. Sie müssten Zeichenarrays oder Bytes verwenden :-) Zeichenfolgenliterale haben eine zusätzliche Eigenschaft: Alle Zeichenfolgenliterale von jedem Klassenpunkt auf dieselbe Zeichenfolge Instanz (sie sind interniert).


0

Es ist fast nicht erforderlich, eine Zeichenfolge neu zu erstellen, da das Literal (die Zeichen in Anführungszeichen) bereits ein Zeichenfolgenobjekt ist, das beim Laden der Hostklasse erstellt wird. Es ist völlig legal, Methoden für ein Literal und Don aufzurufen. Der Hauptunterschied ist die Bequemlichkeit, die Literale bieten. Es wäre ein großer Schmerz und eine Verschwendung von Zeit, wenn wir ein Array von Zeichen erstellen und es char für char füllen müssten und sie einen neuen String (char array) machen müssten.


0

Fühlen Sie sich frei, einen neuen String mit zu erstellen

String s = new String("I'm a new String");

Die übliche Notation s = "new String";ist mehr oder weniger eine praktische Abkürzung - die aus Leistungsgründen verwendet werden sollte, außer in den ziemlich seltenen Fällen, in denen Sie wirklich Strings benötigen, die sich für die Gleichung qualifizieren

(string1.equals(string2)) && !(string1 == string2)

BEARBEITEN

Antwort auf den Kommentar: Dies war kein Hinweis, sondern nur eine direkte Antwort auf die These des Fragestellers, dass wir das Schlüsselwort 'new' für Strings nicht verwenden, was einfach nicht stimmt. Hoffe, diese Bearbeitung (einschließlich der oben genannten) verdeutlicht dies ein wenig. Übrigens - es gibt ein paar gute und viel bessere Antworten auf die obige Frage zu SO.


4
-1 - Schlechter Rat. Sie sollten sich NICHT "frei" fühlen, es sei new String(...)denn, Ihre Anwendung erfordert, dass Sie einen String mit einer eindeutigen Identität erstellen.
Stephen C

1
Ich weiß das. Der Beitrag wurde zur Verdeutlichung bearbeitet.
Andreas Dolk

0

Der Literalpool enthält alle Zeichenfolgen, die ohne Verwendung des Schlüsselworts erstellt wurden new.

Es gibt einen Unterschied: Ein String ohne neue Referenz wird im String-Literal-Pool gespeichert, und ein String mit neuem Code gibt an, dass sie sich im Heap-Speicher befinden.

Zeichenfolgen mit new befinden sich wie jedes andere Objekt an einer anderen Stelle im Speicher.


0

Weil String eine unveränderliche Klasse in Java ist.

Warum ist es nun unveränderlich? Da String unveränderlich ist, kann er von mehreren Threads gemeinsam genutzt werden, und wir müssen den String-Betrieb nicht extern synchronisieren. As String wird auch im Klassenlademechanismus verwendet. Wenn String also veränderbar wäre, hätte java.io.writer in abc.xyz.mywriter geändert werden können


0
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

Ausgabe:

Wahr

Ich habe zwei separate Objekte erstellt, beide haben ein Feld (Ref) 'Name'. Also auch in diesem Fall wird "Jan Peter" geteilt, wenn ich verstehe, wie Java handelt.


0

Nun, der StringPool wird mit The Hashmap in Java implementiert. Wenn wir immer mit einem neuen Schlüsselwort erstellen, wird nicht im Zeichenfolgenpool gesucht und ein neuer Speicher dafür erstellt, der möglicherweise später benötigt wird, wenn eine speicherintensive Operation ausgeführt wird und wenn alle Zeichenfolgen mit einem neuen Schlüsselwort erstellt werden, das die Leistung beeinträchtigen würde unserer Anwendung. Es ist daher ratsam, keine neuen Schlüsselwörter zum Erstellen von Zeichenfolgen zu verwenden, da nur dieser in den Zeichenfolgenpool verschoben wird, der wiederum eine Hashmap ist (Speicherplatz gespart, stellen Sie sich vor, wir haben viele Zeichenfolgen mit neuen Schlüsselwörtern erstellt). Hier wird er gespeichert und gespeichert Wenn die Zeichenfolge bereits vorhanden ist, wird die Referenz (die sich normalerweise im Stapelspeicher befindet) an die neu erstellte Zeichenfolge zurückgegeben. Es wird also getan, um die Leistung zu verbessern.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.