Подтвердить что ты не робот

Сколько строковых объектов в Java?

Мой друг отправил мне вопрос, который он увидел в одном экзамене для сертификации Java о строковых объектах:

String makeStrings(){
    String s = "HI";
    s = s + "5";
    s = s.substring(0,1);
    s = s.toLowerCase();
    return s.toString();
}

Сколько строковых объектов будет создано при вызове этого метода? Правильный ответ на экзамен был 3. Но я думаю, что это пять.

  • "HI"
  • "5"
  • "HI5"
  • "Н"
  • "ч"

Я не прав?

4b9b3361

Ответ 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 в приведенном выше примере?