Программы, как правило, содержат много строковых литералов в своем коде.В Java эти константы собраны во что-то, называемое таблица строк для эффективности.Например, если вы используете строку "Name: "
в десяти разных местах, JVM (как правило) имеет только один экземпляр этой строки и во всех десяти местах, где она используется, все ссылки указывают на этот один экземпляр.Это экономит память.
Эта оптимизация возможна, поскольку String
является неизменным .Если бы можно было изменить строку, то изменив ее в одном месте, это означало бы, что она изменится и в остальных девяти.Вот почему любая операция, которая изменяет строку, возвращает новый экземпляр.Вот почему, если вы сделаете это:
String s = "boink";
s.toUpperCase();
System.out.println(s);
он печатает boink
, а не BOINK
.
Теперь есть еще один хитрый момент: несколько экземпляров java.lang.String
могут указывают на один и тот же базовый char[]
для своих символьных данных, другими словами, они могут быть разными представлениями в одном и том же char[]
, используя только часть массива.Опять же, оптимизация для эффективности.Метод substring()
является одним из случаев, когда это происходит.
s1 = "Fred47";
//String s1: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=0, length=6
// ^........................^
s2 = s1.substring(2, 5);
//String s2: data=[ 'F', 'r', 'e', 'd', '4', '7'], offset=2, length=3
// ^.........^
// the two strings are sharing the same char[]!
В вашем вопросе SCJP все это сводится к:
- Взята строка
"Fred"
из таблицы String. - Строка
"47"
берется из таблицы String. - Строка
"Fred47"
создается во время вызова метода.// 1 - Строка
"ed4"
создается во время вызова метода, совместно использует тот же массив поддержки, что и "Fred47"
// 2 - Строка
"ED4"
создается во время вызова метода.// 3 s.toString()
не создает новый, он просто возвращает this
.
Один интересный крайний случай всего этого: подумайте, что произойдет, если вынапример, очень длинная строка, например веб-страница, взятая из Интернета, скажем, длина char[]
составляет два мегабайта.Если вы возьмете substring(0, 4)
этого, вы получите новую строку, которая выглядит , как будто ее длина составляет всего четыре символа, но она все еще разделяет эти два мегабайта резервных данных.Это не так часто встречается в реальном мире, но это может быть огромной тратой памяти!В (редком) случае, когда вы сталкиваетесь с этим как с проблемой, вы можете использовать new String(hugeString.substring(0, 4))
, чтобы создать строку с новым небольшим резервным массивом.
Наконец, можно принудительно ввести строку в таблицу строк.во время выполнения, позвонив intern()
на него.Основное правило в этом случае: не делай этого.Расширенное правило: не делайте этого, если вы не использовали профилировщик памяти, чтобы убедиться, что это полезная оптимизация.