88 Stimmen

Java-Zeichenfolgen: "String s = new String("albern");"

Ich bin ein C++-Typ, der Java lernt. Ich lese Effective Java und etwas hat mich verwirrt. Es sagt, man solle niemals Code wie diesen schreiben:

String s = new String("silly");

Da es unnötige String-Objekte erstellt. Stattdessen sollte es so geschrieben werden:

String s = "Nicht mehr albern";

Ok bis hierher ... Aber, gegeben diese Klasse:

public final class CaseInsensitiveString {
    private String s;
    public CaseInsensitiveString(String s) {
        if (s == null) {
            throw new NullPointerException();
        }
        this.s = s;
    }
    :
    :
}

CaseInsensitiveString cis = new CaseInsensitiveString("Polnisch");
String s = "polnisch";
  1. Warum ist die erste Aussage in Ordnung? Sollte es nicht sein

    CaseInsensitiveString cis = "Polnisch";

  2. Wie mache ich CaseInsensitiveString so, dass es sich wie String verhält, damit die obige Aussage in Ordnung ist (mit und ohne Erweiterung von String)? Was macht String zu etwas, das es erlaubt, einfach einen Literal zu übergeben? Nach meinem Verständnis gibt es kein Konzept des "Kopierkonstruktors" in Java?

2 Stimmen

String str1 = "foo"; String str2 = "foo"; Beide str1 und str2 gehören zum selben String-Objekt, "foo", da Java Strings im StringPool verwaltet, sodass eine neue Variable auf denselben String verweist und nicht einen anderen erstellt, sondern den bereits im StringPool vorhandenen zuweist. Aber wenn wir dies tun: String str1 = new String("foo"); String str2 = new String("foo"); Hier gehören sowohl str1 als auch str2 zu verschiedenen Objekten, da new String() zwangsläufig ein neues String-Objekt erstellt.

115voto

Adam Rosenfield Punkte 373807

String ist eine spezielle integrierte Klasse der Sprache. Es handelt sich nur um die String-Klasse, bei der du vermeiden solltest, zu sagen

String s = new String("Polish");

Weil das Literal "Polish" bereits vom Typ String ist und du dadurch ein zusätzliches unnötiges Objekt erstellst. Für jede andere Klasse ist es korrekt (und in diesem Fall die einzige Aktion), zu sagen

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

ist das Richtige zu tun.

9 Stimmen

Ein weiterer Punkt ist, dass der Compiler mit Zeichenfolgenliterale, die nicht unbedingt mit einem so eigenartigen Funktionsaufruf wie "String(literal)" möglich sind, eine internige/propagierende Verarbeitung durchführen kann.

6 Stimmen

Da du niemals new String("foo") aufrufen solltest, fragst du dich vielleicht, warum der Konstruktor new String(String) existiert. Die Antwort ist, dass es manchmal eine gute Verwendung dafür gibt: stackoverflow.com/a/390854/1442870

0 Stimmen

Zur Info: Der Kommentar von Tetha oben hat das Wort "interning" falsch geschrieben, wie in string interning.

58voto

Leigh Punkte 4198

Ich glaube, der Hauptvorteil der Verwendung der Literalform (dh "foo" statt new String("foo")) besteht darin, dass alle String-Literale von der VM 'interned' werden. Mit anderen Worten, es wird zu einem Pool hinzugefügt, so dass jeder andere Code, der dieselbe Zeichenkette erstellt, die gepoolte Zeichenkette anstelle einer neuen Instanz verwendet.

Zur Veranschaulichung: Der folgende Code gibt true für die erste Zeile aus, aber false für die zweite:

System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));

15 Stimmen

Ebenso muss man laut FindBugs "new Integer(N)" durch "Integer.valueOf(N)" ersetzen, aufgrund des Internings.

6 Stimmen

Sie sollten auch hinzufügen, dass "foo" == new String("foo").intern()

5 Stimmen

Eine Korrektur: Zeichenkettenliterale werden vom Compiler gemacht, um auf dieselbe Referenz zu zeigen, nicht die VM. Die VM kann String-Objekte zur Laufzeit internieren, daher kann die zweite Zeile true oder false zurückgeben!

30voto

Steve B. Punkte 52372

Saiten werden in Java etwas speziell behandelt, sie sind unveränderlich, sodass es sicher ist, sie durch Referenzzählung zu handhaben.

Wenn Sie Folgendes eingeben

String s = "Polish";
String t = "Polish";

dann beziehen sich s und t tatsächlich auf dasselbe Objekt, und s==t gibt true zurück, für "==" für Objekte bedeutet "ist dasselbe Objekt" (oder kann es sowieso, ich bin mir nicht sicher, ob dies Teil der tatsächlichen Sprachspezifikation ist oder einfach ein Detail der Compiler-Implementierung - also vielleicht ist es nicht sicher, sich darauf zu verlassen) .

Wenn Sie Folgendes eingeben

String s = new String("Polish");
String t = new String("Polish");

dann s!=t (weil Sie explizit eine neue Zeichenfolge erstellt haben), obwohl s.equals(t) true zurückgibt (weil String dieses Verhalten zu equals hinzufügt).

Das, was Sie schreiben möchten,

CaseInsensitiveString cis = "Polish";

funktioniert nicht, weil Sie denken, dass die Anführungszeichen eine Art Kurzschlusskonstruktor für Ihr Objekt sind, wenn dies tatsächlich nur für normale java.lang.Strings funktioniert.

0 Stimmen

+1 für die Erwähnung der Unveränderlichkeit, die für mich der eigentliche Grund ist, warum man in Java strA = strB schreibt, anstatt strA = new String(strB). Es hat wirklich nicht viel mit der String-Internierung zu tun.

0 Stimmen

Sie werden nicht durch Referenzzählung behandelt. String-Pooling wird vom JLS benötigt.

20voto

Vikas Punkte 460
String s1="foo";

der Literal landet im Pool und s1 wird darauf verweisen.

String s2="foo";

Dieses Mal wird überprüft, ob der Literal "foo" bereits im StringPool vorhanden ist, da er jetzt existiert, wird s2 auf denselben Literal verweisen.

String s3=new String("foo");

Der Literal "foo" wird zuerst im StringPool erstellt, dann wird durch den String-Argument-Konstruktor ein String-Objekt erstellt, d.h. "foo" im Heap aufgrund der Objekterstellung durch den new-Operator, dann wird s3 darauf verweisen.

String s4=new String("foo");

genau wie s3

also System.out.println(s1==s2);// **true** aufgrund des Literalvergleichs.

und System.out.println(s3==s4);// **false** aufgrund des Objektvergleichs

(s3 und s4 werden an unterschiedlichen Orten im Heap erstellt)

1 Stimmen

Verwenden Sie keine Anführungszeichen für Text, der nicht zitiert wird, und verwenden Sie Code-Formatierung für Code.

12voto

Alnitak Punkte 324207

Strings sind in Java speziell - sie sind unveränderlich, und Zeichenkettenkonstanten werden automatisch in String-Objekte umgewandelt.

Es gibt keine Möglichkeit für Ihr SomeStringClass cis = "value"-Beispiel, auf eine andere Klasse anzuwenden.

Sie können auch nicht String erweitern, da es als final deklariert ist, was bedeutet, dass keine Unterklassierung erlaubt ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X