Сколько строковых объектов в Java?
Мой друг отправил мне вопрос, который он увидел в одном экзамене для сертификации Java о строковых объектах:
String makeStrings(){
String s = "HI";
s = s + "5";
s = s.substring(0,1);
s = s.toLowerCase();
return s.toString();
}
Сколько строковых объектов будет создано при вызове этого метода?
Правильный ответ на экзамен был 3. Но я думаю, что это пять.
Я не прав?
Ответы
Ответ 1
String makeStrings() {
String s = "HI"; //String literal
s = s + "5"; //concatenation creates new String object (1)
s = s.substring(0,1); //creates new String object (2)
s = s.toLowerCase(); //creates new String object (3)
return s.toString(); //returns already defined String
}
Что касается конкатенации, при создании новой строки JVM
используется StringBuilder
, то есть:
s = new StringBuilder(s).append("5").toString();
toString()
для a StringBuilder
:
public String toString() {
return new String(value, 0, count); //so a new String is created
}
substring
создает новый объект String , если не проиндексирован весь String
:
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex)
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
toString()
выполняет НЕ создание новой строки:
public String toString()
{
return this;
}
toLowerCase()
- довольно длинный метод, но достаточно сказать, что если String
не уже во всех строчных строках, он будет возвращать new String
.
Учитывая, что предоставленный ответ 3
, как предложил Jon Skeet, мы можем предположить, что оба литерала String уже находятся в пуле String. Для получения дополнительной информации о том, когда строки добавлены в пул, см. Вопросы о пуле Java String.
Ответ 2
s = s + "5";
Переводится на:
String s = new StringBuilder(s).append("5").toString();
Пока создается один объект.
s = s.substring(0,1);
Создает новую строку.
s = s.toLowerCase();
Создает новый объект.
return s.toString();
Не создает String, он возвращает уже созданную.
Ответ 3
Некоторые из других ответов имеют смысл, но как насчет строкового литерала?
String s = "HI";
Для строковых литералов, когда файл .java скомпилирован в файл .class, любые строковые литералы отмечены особым образом, как и все константы. Когда класс загружен (обратите внимание, что загрузка происходит до инициализации), JVM просматривает код для класса и ищет строковые литералы.
Когда он найдет один, он проверяет, уже ли эквивалентная строка ссылаясь на кучу. Если нет, он создает экземпляр String на куча и сохраняет ссылку на этот объект в таблице констант
После ссылки на этот строковый объект любые ссылки на этот строковый литерал в вашей программе просто заменяются ссылкой на объект, на который ссылается пул строк.
Следовательно, должно быть четыре объекта Java, хотя, когда один и тот же метод вызывается снова и снова, тогда будет только три объекта, как в приложении, пул строковых литералов содержит литерал "HI".
Кроме того, для получения дополнительной информации о том, почему новые объекты создаются при вытеснении вышеперечисленных блоков методов, мы также можем проверить хэш-коды, которые различны для разных строк (String
является неизменяемым.)
public static void main(String[] args)
{
NumberOfString str = new NumberOfString();
String s = str.makeStrings();
System.out.println(s.hashCode());
}
public String makeStrings()
{
String s = "HI";
System.out.println(s.hashCode());
s = s + "5";
System.out.println(s.hashCode());
s = s.substring(0, 1);
System.out.println(s.hashCode());
s = s.toLowerCase();
System.out.println(s.hashCode());
return s.toString();
}
Вы получаете следующий результат:
2305
71508
72
104
104
Не следует ли считать в литерале String в приведенном выше примере?