Передача строки по ссылке в Java?

Я использую следующее в C:

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

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

И результат:

foo

Однако в Java это, похоже, не работает. Я предполагаю, что объект String копируется, а не передается по ссылке. Я думал, что Строки были объектами, которые всегда передаются по ссылке.

Что здесь происходит?

4b9b3361

У вас есть три варианта:

  1. Используйте StringBuilder:

    StringBuilder zText = new StringBuilder ();
    void fillString(StringBuilder zText) { zText.append ("foo"); }
    
  2. Создайте класс контейнера и передайте экземпляр контейнера в ваш метод:

    public class Container { public String data; }
    void fillString(Container c) { c.data += "foo"; }
    
  3. Создайте массив:

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

С точки зрения производительности, StringBuilder обычно является лучшим вариантом.

156
ответ дан 13 авг. '09 в 11:30
источник

В Java ничего не передается по ссылке. Все передано значением. Ссылки на объекты передаются по значению. Кроме того, строки неизменяемы. Поэтому, когда вы добавляете в переданную строку, вы просто получаете новую строку. Вы можете использовать возвращаемое значение или вместо этого передать StringBuffer.

63
ответ дан 13 авг. '09 в 11:30
источник

Что происходит, так это то, что ссылка передается по значению, т.е. передается копия ссылки. Ничто в java не передается по ссылке, и поскольку строка является неизменной, это присваивание создает новый строковый объект, на который указывает копия ссылки. Исходная ссылка по-прежнему указывает на пустую строку.

Это будет одинаково для любого объекта, т.е. установить его в новое значение в методе. Пример ниже просто делает то, что происходит более очевидным, но конкатенация строки - это одно и то же.

void foo( object o )
{
    o = new Object( );  // original reference still points to old value on the heap
}
43
ответ дан 13 авг. '09 в 11:32
источник

объекты передаются по ссылке, примитивы передаются по значению.

Строка не является примитивным, это объект, и это особый случай объекта.

Это предназначено для экономии памяти. В JVM существует пул строк. Для каждой созданной строки JVM попытается увидеть, существует ли такая же строка в пуле строк и указать на нее, если ее уже было.

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));
    }
}

/* OUTPUT */

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

== проверяет адрес памяти (ссылку), а .equals проверяет содержимое (значение)

8
ответ дан 14 авг. '09 в 2:55
источник

String - неизменяемый объект в Java. Вы можете использовать класс StringBuilder для выполнения задания, которое вы пытаетесь выполнить, следующим образом:

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");
}

Другой вариант - создать класс со строкой в ​​качестве переменной области (сильно обескуражен) следующим образом:

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
ответ дан 01 июля '13 в 2:27
источник

Строки передаются по ссылке (ну, строго говоря, как отмечает Эд Свангрен, ссылка на строку передается по значению), но они неизменяемы.

zText += foo;

эквивалентно

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

То есть, он изменяет (локальную) переменную zText, так что теперь она указывает на новую ячейку памяти, в которой находится String с исходным содержимым zText, при добавлении "foo". Исходный объект не изменяется, а локальная переменная main() zText по-прежнему указывает на исходную (пустую) строку.

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);
  }

}

печатает

Original value:
Local value: foo
Final value:

Если вы хотите изменить строку, вы можете, как указано, использовать StringBuilder, а также некоторый контейнер (массив или пользовательский класс контейнера), который дает вам дополнительный уровень указателя. Кроме того, просто верните новое значение и назначьте его:

class StringFiller2 {

  static StringfillString(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);
  }

}

печатает

Original value:
Local value: foo
Final value: foo

Это, пожалуй, самое Java-подобное решение в общем случае - см. Эффективный элемент Java "Стабильность неизменности".

Как уже отмечалось, StringBuilder часто дает вам лучшую производительность - если у вас есть много приложений для добавления, особенно внутри цикла, используйте StringBuilder.

Но попробуйте передать неизменяемый Strings, а не изменяемый StringBuilders, если можете - ваш код будет легче читать и более ремонтопригодным. Подумайте о создании своих параметров final и настройке среды IDE, чтобы предупредить вас, когда вы переназначите параметр метода на новое значение.

3
ответ дан 13 авг. '09 в 11:43
источник

Ответ прост. В java строки неизменяемы. Следовательно, это похоже на использование "final" модификатора (или "const" в C/С++). Итак, как только вы назначены, вы не можете изменить его так, как вы.

Вы можете изменить значение, на которое указывает строка, но вы не можете изменить фактическое значение, на которое указывает эта строка.

Т.е. String s1 = "hey". Вы можете сделать s1 = "woah", и это полностью нормально, но вы не можете фактически изменить базовое значение строки (в данном случае: "hey" ), чтобы быть чем-то еще после того, как ее назначили с помощью plusEquals и т.д. (Т. Е. s1 += " whatup != "hey whatup").

Для этого используйте классы StringBuilder или StringBuffer или другие изменяемые контейнеры, а затем просто вызовите .toString(), чтобы преобразовать объект обратно в строку.

note: Строки часто используются в качестве хеш-ключей, поэтому эта часть причины, по которой они являются неизменяемыми.

2
ответ дан 07 апр. '14 в 22:09
источник

Строка неизменна в java. вы не можете изменять/изменять, существующий строковый литерал/объект.

String s = "Hello"; S = S + "Привет" ;

Здесь предыдущая ссылка s заменяется новой ссылкой, указывающей на значение "HelloHi".

Однако для приведения изменчивости мы имеем StringBuilder и StringBuffer.

StringBuilder s = new StringBuilder(); s.append( "Привет" );

это добавляет новое значение "Привет" к той же ссылке. //

1
ответ дан 25 сент. '17 в 10:23
источник

В этом случае используется 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");
}
}

Еще лучше использовать 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
ответ дан 20 мая '13 в 17:07
источник

String - специальный класс в Java. Это Thread Save, что означает: "После создания экземпляра String содержимое экземпляра String никогда не будет изменено".

Вот что происходит для

 zText += "foo";

Во-первых, компилятор Java получит значение экземпляра zText String, а затем создаст новый экземпляр String, значение которого zText добавляет "foo". Итак, вы знаете, почему экземпляр, который zText указывает на, не изменился. Это совершенно новый пример. Фактически, даже String "foo" является новым экземпляром String. Итак, для этого утверждения Java создаст два экземпляра String, один - "foo", другой - значение zText append "foo". Правило простое: значение экземпляра String никогда не будет изменено.

Для метода fillString вы можете использовать параметр StringBuffer как параметр, или вы можете его изменить следующим образом:

String fillString(String zText) {
    return zText += "foo";
}
1
ответ дан 13 авг. '09 в 12:23
источник

У Аарона Дигуллы есть лучший ответ. Вариантом его второго варианта является использование оболочки или класса контейнера MutableObject библиотеки commons lang версии 3 +:

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

вы сохраняете объявление класса контейнера. Недостатком является зависимость от сообщества lang lib. Но lib имеет довольно много полезной функции и почти любой более крупный проект, над которым я работал, использовал его.

0
ответ дан 24 нояб. '14 в 0:58
источник