webentwicklung-frage-antwort-db.com.de

Übergeben einer Zeichenfolge als Referenz in Java?

Ich bin es gewohnt, in C Folgendes zu tun:

void main() {
    String zText = "";
    fillString(zText);
    printf(zText);
}

void fillString(String zText) {
    zText += "foo";
}

Und die Ausgabe ist:

foo

In Java scheint dies jedoch nicht zu funktionieren. Ich gehe davon aus, dass das String -Objekt kopiert anstelle von übergeben durch referenziert ist. Ich dachte, Strings wären Objekte, die immer als Referenz übergeben werden.

Was geht hier vor sich?

146
Soren Johnson

Sie haben drei Möglichkeiten:

  1. Verwenden Sie einen StringBuilder:

    StringBuilder zText = new StringBuilder ();
    void fillString(StringBuilder zText) { zText.append ("foo"); }
    
  2. Erstellen Sie eine Containerklasse und übergeben Sie eine Instanz des Containers an Ihre Methode:

    public class Container { public String data; }
    void fillString(Container c) { c.data += "foo"; }
    
  3. Erstellen Sie ein Array:

    new String[] zText = new String[1];
    zText[0] = "";
    
    void fillString(String[] zText) { zText[0] += "foo"; }
    

In Bezug auf die Leistung ist der StringBuilder normalerweise die beste Option.

185
Aaron Digulla

In Java wird nichts als Referenz übergeben . Alles ist als Wert übergeben. Objektreferenzen werden als Wert übergeben. Zusätzlich sind Strings nveränderlich. Wenn Sie also an den übergebenen String anhängen, erhalten Sie nur einen neuen String. Sie können stattdessen einen Rückgabewert verwenden oder einen StringBuffer übergeben.

81
zedoo

Was geschieht, ist, dass die Referenz als Wert übergeben wird, d. H. Eine Kopie der Referenz wird übergeben. Nichts in Java wird als Referenz übergeben, und da eine Zeichenfolge unveränderlich ist, erstellt diese Zuweisung ein neues Zeichenfolgenobjekt, auf das die Kopie der Referenz jetzt verweist Der Verweis zeigt immer noch auf die leere Zeichenfolge.

Dies ist für jedes Objekt gleich, d. H., Es wird in einer Methode auf einen neuen Wert gesetzt. Das folgende Beispiel verdeutlicht nur, was vor sich geht, aber die Verkettung einer Zeichenfolge ist wirklich dasselbe.

void foo( object o )
{
    o = new Object( );  // original reference still points to old value on the heap
}
49
Ed S.

Java.lang.String ist unveränderlich.

Ich hasse es, URLs einzufügen, aber https://docs.Oracle.com/javase/10/docs/api/Java/lang/String.html ist wichtig, damit Sie lesen und verstehen, wenn Sie sich in befinden Java-Land.

18
Ryan Fernandes

objekte werden als Referenz übergeben, Primitive als Wert.

String ist kein Primitiv, es ist ein Objekt und es ist ein Sonderfall von Objekt.

Dies dient zum Speichern. In JVM gibt es einen String-Pool. Bei jeder erstellten Zeichenfolge versucht JVM, festzustellen, ob dieselbe Zeichenfolge im Zeichenfolgenpool vorhanden ist, und verweist darauf, wenn bereits eine vorhanden ist.

public class TestString
{
    private static String a = "hello world";
    private static String b = "hello world";
    private static String c = "hello " + "world";
    private static String d = new String("hello world");

    private static Object o1 = new Object();
    private static Object o2 = new Object();

    public static void main(String[] args)
    {
        System.out.println("a==b:"+(a == b));
        System.out.println("a==c:"+(a == c));
        System.out.println("a==d:"+(a == d));
        System.out.println("a.equals(d):"+(a.equals(d)));
        System.out.println("o1==o2:"+(o1 == o2));

        passString(a);
        passString(d);
    }

    public static void passString(String s)
    {
        System.out.println("passString:"+(a == s));
    }
}

/* AUSGABE */

a==b:true
a==c:true
a==d:false
a.equals(d):true
o1==o2:false
passString:true
passString:false

das == prüft auf Speicheradresse (Referenz) und das .equals prüft auf Inhalt (Wert)

7
janetsmith

Alle Argumente in Java werden als Wert übergeben. Wenn Sie String an eine Funktion übergeben, wird der übergebene Wert ist ein Verweis auf ein String-Objekt Sie können diesen Verweis jedoch nicht ändern, und das zugrunde liegende String-Objekt ist unveränderlich.

Die Zuordnung

zText += foo;

ist äquivalent zu:

zText = new String(zText + "foo");

Das heißt, es weist (lokal) den Parameter zText als neue Referenz zu, die auf einen neuen Speicherort verweist, in dem sich ein neuer String befindet, der den ursprünglichen Inhalt von zText mit "foo" angehängt.

Das ursprüngliche Objekt wird nicht geändert, und die lokale Variable main() der Methode zText zeigt weiterhin auf die ursprüngliche (leere) Zeichenfolge.

class StringFiller {
  static void fillString(String zText) {
    zText += "foo";
    System.out.println("Local value: " + zText);
  }

  public static void main(String[] args) {
    String zText = "";
    System.out.println("Original value: " + zText);
    fillString(zText);
    System.out.println("Final value: " + zText);
  }
}

druckt:

Original value:
Local value: foo
Final value:

Wenn Sie die Zeichenfolge ändern möchten, können Sie, wie bereits erwähnt, StringBuilder oder einen Container (ein Array oder eine AtomicReference oder eine benutzerdefinierte Containerklasse) verwenden, der Ihnen eine zusätzliche Ebene der Zeiger-Indirektion bietet. Alternativ können Sie den neuen Wert auch einfach zurückgeben und zuweisen:

class StringFiller2 {
  static String fillString(String zText) {
    zText += "foo";
    System.out.println("Local value: " + zText);
    return zText;
  }

  public static void main(String[] args) {
    String zText = "";
    System.out.println("Original value: " + zText);
    zText = fillString(zText);
    System.out.println("Final value: " + zText);
  }
}

druckt:

Original value:
Local value: foo
Final value: foo

Dies ist wahrscheinlich die Java-ähnlichste Lösung im allgemeinen Fall - siehe Effektives Java Punkt "Unveränderlichkeit bevorzugen".

Wie bereits erwähnt, erzielen Sie mit StringBuilder häufig eine bessere Leistung. Wenn Sie vor allem in einer Schleife viel anhängen müssen, verwenden Sie StringBuilder.

Versuchen Sie jedoch, unveränderliches Strings und nicht veränderliches StringBuilders weiterzugeben, wenn Sie können - Ihr Code wird einfacher zu lesen und leichter zu warten sein. Erwägen Sie, Ihre Parameter final zu definieren und IDE) zu konfigurieren, um Sie zu warnen, wenn Sie einen Methodenparameter einem neuen Wert zuweisen.

6
David Moles

String ist ein unveränderliches Objekt in Java. Mit der StringBuilder-Klasse können Sie die Aufgabe ausführen, die Sie ausführen möchten:

public static void main(String[] args)
{
    StringBuilder sb = new StringBuilder("hello, world!");
    System.out.println(sb);
    foo(sb);
    System.out.println(sb);

}

public static void foo(StringBuilder str)
{
    str.delete(0, str.length());
    str.append("String has been modified");
}

Eine andere Möglichkeit besteht darin, eine Klasse mit einer Zeichenfolge als Bereichsvariable (von der dringend abgeraten wird) wie folgt zu erstellen:

class MyString
{
    public String value;
}

public static void main(String[] args)
{
    MyString ms = new MyString();
    ms.value = "Hello, World!";

}

public static void foo(MyString str)
{
    str.value = "String has been modified";
}
5

String ist eine spezielle Klasse in Java. Es ist Thread-sicher, was bedeutet, dass der Inhalt der String-Instanz nach dem Erstellen einer String-Instanz niemals geändert wird.

Hier ist, was los ist

 zText += "foo";

Zuerst ruft der Java - Compiler den Wert der zText String-Instanz ab und erstellt dann eine neue String-Instanz, deren Wert zText ist, wobei "foo" angehängt wird. Damit wissen Sie, warum sich die Instanz, auf die zText zeigt, nicht ändert Es ist eine völlig neue Instanz. Tatsächlich ist sogar String "foo" eine neue String-Instanz. Für diese Anweisung erzeugt Java erstellt zwei String-Instanzen, eine ist "foo", Ein weiteres Beispiel ist der Wert von zText append "foo". Die Regel ist einfach: Der Wert der String-Instanz wird niemals geändert.

Für die Methode fillString können Sie einen StringBuffer als Parameter verwenden oder wie folgt ändern:

String fillString(String zText) {
    return zText += "foo";
}
2
DeepNightTwo

Die Antwort ist einfach. In Java Strings sind unveränderlich. Daher wird der Modifikator 'final' (oder 'const' in C/C++) verwendet. Einmal zugewiesen, können Sie ihn also nicht mehr so ​​ändern, wie Sie es getan haben.

Sie können welches den Wert ändern, auf den eine Zeichenfolge verweist, aber Sie können den tatsächlichen Wert, auf den diese Zeichenfolge aktuell verweist, NICHT ändern.

Dh String s1 = "hey". Du kannst das schaffen s1 = "woah", und das ist völlig in Ordnung, aber Sie können den zugrunde liegenden Wert des Strings (in diesem Fall: "hey") nicht ändern, um etwas anderes zu sein, wenn er mit plusEquals usw. zugewiesen wurde (dh s1 += " whatup != "hey whatup").

Verwenden Sie dazu die StringBuilder- oder StringBuffer-Klassen oder andere veränderbare Container und rufen Sie dann einfach .toString () auf, um das Objekt wieder in einen String zu konvertieren.

hinweis: Strings werden oft als Hash-Schlüssel verwendet, daher ist dies ein Grund, warum sie unveränderlich sind.

2
ak_2050

Dies funktioniert mit StringBuffer

public class test {
 public static void main(String[] args) {
 StringBuffer zText = new StringBuffer("");
    fillString(zText);
    System.out.println(zText.toString());
 }
  static void fillString(StringBuffer zText) {
    zText .append("foo");
}
}

Verwenden Sie noch besser StringBuilder

public class test {
 public static void main(String[] args) {
 StringBuilder zText = new StringBuilder("");
    fillString(zText);
    System.out.println(zText.toString());
 }
  static void fillString(StringBuilder zText) {
    zText .append("foo");
}
}
1
Mohammed Rafeeq

String ist in Java unveränderlich. Sie können ein vorhandenes Zeichenfolgenliteral/-objekt nicht ändern.

String s = "Hallo"; s = s + "hi";

Hier wird die vorherige Referenz durch die neue Referenz ersetzt, die auf den Wert "HelloHi" verweist.

Wir haben jedoch StringBuilder und StringBuffer, um die Veränderbarkeit zu erhöhen.

StringBuilder s = new StringBuilder (); am append ("Hi");

damit wird der neue Wert "Hi" an dieselbe Referenz angehängt. //

1
gauravJ

Strings sind nveränderlich in Java.

1

Wenn Sie ein Objekt (einschließlich String) in Java als Referenz übergeben möchten, übergeben Sie es möglicherweise als Mitglied eines umgebenden Adapters. Eine Lösung mit einem generischen ist hier:

import Java.io.Serializable;

public class ByRef<T extends Object> implements Serializable
{
    private static final long serialVersionUID = 6310102145974374589L;

    T v;

    public ByRef(T v)
    {
        this.v = v;
    }

    public ByRef()
    {
        v = null;
    }

    public void set(T nv)
    {
        v = nv;
    }

    public T get()
    {
        return v;
    }

// ------------------------------------------------------------------

    static void fillString(ByRef<String> zText)
    {
        zText.set(zText.get() + "foo");
    }

    public static void main(String args[])
    {
        final ByRef<String> zText = new ByRef<String>(new String(""));
        fillString(zText);
        System.out.println(zText.get());
    }
}
0
Sam Ginrich

Für jemanden, der neugieriger ist

class Testt {
    static void Display(String s , String varname){
        System.out.println(varname + " variable data = "+ s + " :: address hashmap =  " + s.hashCode());
    }

    static void changeto(String s , String t){
        System.out.println("entered function");
        Display(s , "s");
        s = t ;
        Display(s,"s");
        System.out.println("exiting function");
    }

    public static void main(String args[]){
        String s =  "hi" ;
        Display(s,"s");
        changeto(s,"bye");
        Display(s,"s");
    }
}

Wenn Sie nun diesen obigen Code ausführen, können Sie sehen, wie sich die Adresse hashcodes mit der Zeichenfolgenvariablen s ändert. Ein neues Objekt wird der Variablen s in der Funktion changeto zugewiesen, wenn s geändert wird

0
Rajesh kumar

Aaron Digulla hat die bisher beste Antwort. Eine Variante seiner zweiten Option ist die Verwendung der Wrapper- oder Containerklasse MutableObject der commons lang library Version 3+:

void fillString(MutableObject<String> c) { c.setValue(c.getValue() + "foo"); }

sie speichern die Deklaration der Containerklasse. Der Nachteil ist eine Abhängigkeit von der commons lang lib. Aber die Bibliothek hat eine Menge nützlicher Funktionen und fast jedes größere Projekt, an dem ich gearbeitet habe, hat sie benutzt.

0
user2606740