Струны - как они работают? - PullRequest
3 голосов
/ 17 августа 2011

Как String объекты работают в Java? Как термин «неизменяемый» в точности применяется к строковым объектам? Почему мы не видим измененную строку после прохождения через какой-либо метод, хотя мы работаем с исходным значением строкового объекта?

Ответы [ 5 ]

12 голосов
/ 17 августа 2011

Строка имеет приватный финал char[].когда создается новый объект String, массив также создается и заполняется.к нему нельзя получить доступ позже [извне] или изменить [на самом деле это можно сделать с помощью отражения, но мы оставим это в стороне].

это «неизменяемый», поскольку после создания строки ее значение не можетПри изменении строки «корова» всегда будет иметь значение «корова».

Мы не видим измененную строку, поскольку она неизменна, один и тот же объект никогда не будет изменен, независимо от того, что вы с ним делаете[помимо изменения с отражением].поэтому "корова" + "лошадь" создадут новый объект String и НЕ изменят последний объект.

, если вы определите:

void foo(String arg) {
  arg= arg + " horse";
}

и вы вызовете:

String str = "cow";
foo(str);

str, где вызов не изменен [поскольку это исходная ссылка на тот же объект!] Когда вы изменили arg, вы просто изменили его, чтобы ссылаться на другой объект Stringи НЕ изменил фактический исходный объект.поэтому str будет тем же объектом, который не был изменен, все еще содержащий "cow"

, если вы все еще хотите изменить объект String, вы можете сделать это с отражением.Однако, это без консультации и может иметь некоторые серьезные побочные эффекты:

    String str = "cow";
    try { 
    Field value = str.getClass().getDeclaredField("value");
    Field count = str.getClass().getDeclaredField("count");
    Field hash = str.getClass().getDeclaredField("hash");
    Field offset = str.getClass().getDeclaredField("offset");
    value.setAccessible(true);
    count.setAccessible(true);
    hash.setAccessible(true);
    offset.setAccessible(true);
    char[] newVal = { 'c','o','w',' ','h','o','r','s','e' };
    value.set(str,newVal);
    count.set(str,newVal.length);
    hash.set(str,0);
    offset.set(str,0);
    } catch (NoSuchFieldException e) {
    } catch (IllegalAccessException e) {}
    System.out.println(str);
}
4 голосов
/ 17 августа 2011

Из учебника :

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

2 голосов
/ 17 августа 2011

Строки в Java неизменны (состояние нельзя изменить после создания).Это открывает возможности для оптимизации.Одним из примеров является интернирование строк, где строковые литералы поддерживаются в пуле строк, а новые объекты String создаются только в том случае, если конкретный строковый литерал еще не существует в пуле.Если строковый литерал уже существует, возвращается ссылка.Это может быть выполнено только потому, что строки являются неизменяемыми, поэтому вам не нужно беспокоиться о том, что какой-либо объект, содержащий ссылку, изменит его.

Методы, которые появляются для изменения строки, фактически возвращают новый экземпляр.Одним из примеров является конкатенация строк:

String s = "";
for( int i = 0; i < 5; i++ ){
    s = s + "hi";
}

Что на самом деле происходит внутри (компилятор меняет его):

String s = "";
for( int i = 0; i < 5; i++ ){
    StringBuffer sb = new StringBuffer();
    sb.append(s);
    sb.append("hi");
    s = sb.toString();
}

Вы можете ясно видеть, что новые экземпляры создаются методом toString (примечаниечто это может быть сделано более эффективным путем непосредственного использования StringBuffers).StringBuffers непостоянны, в отличие от Strings.

0 голосов
/ 17 августа 2011

Я думаю, эта ссылка поможет вам понять, как действительно работает Java String

Теперь рассмотрим следующий код -

String s = "ABC"; s.toLowerCase(); Метод toLowerCase () будетне изменять данные "ABC", которые содержатся.Вместо этого создается новый объект String, которому при создании создаются данные "abc".Ссылка на этот объект String возвращается методом toLowerCase ().Чтобы String содержал данные «abc», необходим другой подход.

Снова рассмотрим следующее - s = s.toLowerCase();

Теперь String ссылается на новый объект String, который содержит "а».В синтаксисе объявления класса String нет ничего, что делает его неизменным;скорее, ни один из методов класса String никогда не влияет на данные, содержащиеся в объекте String, что делает его неизменным.

Я не совсем понял ваш третий вопрос.Может быть, предоставить кусок кода и рассказать о своей проблеме - лучший вариант.Надеюсь, что это поможет.

Вы также можете заглянуть в этот blogpost для большего понимания

[примеры кода взяты из вики.Вы также можете посмотреть там для получения дополнительной информации]

0 голосов
/ 17 августа 2011

Каждый объект имеет состояние . Состояние объекта String - это массив символов, которые составляют String, например, String "foo" содержит массив ['f', 'o', 'o']. Поскольку строка неизменна , этот массив не может никогда быть изменен каким-либо образом, формой или формой.

Каждый метод в каждом классе, который хочет изменить строку, должен вместо этого возвращать новую строку, которая представляет измененное состояние старой строки. То есть, если вы попытаетесь изменить «foo», вы получите новый строковый объект с внутренним состоянием ['o', 'o', 'f'].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...