Строковый объект. Требуется уточнение - PullRequest
4 голосов
/ 15 июня 2010

Скажите, у меня есть следующая строка в моей программе:

jobSetupErrors.append("abc");

В приведенном выше случае, где jobSetupErrors - это StringBuilder (), я вижу следующее:

  1. Новый объект String создан и ему присвоено значение "abc"
  2. значение этого объекта String присваивается существующему объекту StringBuilder

Если это правильно, и я добавляю еще 1 строку ...

jobSetupErrors.append("abc");
logger.info("abc");

В приведенном выше примере мы создаем объект String отдельно 2 раза?

Если это так, было бы правильнее сделать что-то подобное?

String a = "abc";
jobSetupErrors.append(a);
logger.info(a);

Это лучший подход? Пожалуйста, сообщите

Ответы [ 2 ]

8 голосов
/ 15 июня 2010

В приведенном выше примере мы создаем Строковый объект отдельно 2 раза?

Нет, потому что в Java строковые литералы (все что в двойных кавычках) интернированы. Это означает, что обе эти строки ссылаются на один и тот же String, поэтому дальнейшая оптимизация не требуется.

Во втором примере вы только создаете дополнительную ссылку на тот же String, но это то, что Java уже сделала для вас, поместив ссылку на нее в нечто, называемое пулом строк. Это происходит в первый раз, когда он видит «abc»; во второй раз он проверяет пул и обнаруживает, что «abc» уже существует, поэтому он заменяется той же ссылкой, что и первая.

См. http://en.wikipedia.org/wiki/String_interning для получения дополнительной информации об интернировании строк.

4 голосов
/ 15 июня 2010

Чтобы помочь выяснить это, я написал класс, подобный следующему:

class Test {
  String a = "abc" ;
  StringBuilder buffer = new StringBuilder() ;

  public void normal() {
    buffer.append( "abc" ) ;
    buffer.append( "abc" ) ;
  }

  public void clever() {
    buffer.append( a ) ;
    buffer.append( a ) ;
  }
}

Если мы скомпилируем это, а затем запустим над ним javap, чтобы извлечь байт-код:

14:09:58 :: javap $ javap -c Test
Compiled from "Test.java"
class Test extends java.lang.Object{
java.lang.String a;

java.lang.StringBuilder buffer;

Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   ldc #2; //String abc
   7:   putfield    #3; //Field a:Ljava/lang/String;
   10:  aload_0
   11:  new #4; //class java/lang/StringBuilder
   14:  dup
   15:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   18:  putfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   21:  return

public void normal();
  Code:
   0:   aload_0
   1:   getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   4:   ldc #2; //String abc
   6:   invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   9:   pop
   10:  aload_0
   11:  getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   14:  ldc #2; //String abc
   16:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  pop
   20:  return

public void clever();
  Code:
   0:   aload_0
   1:   getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   4:   aload_0
   5:   getfield    #3; //Field a:Ljava/lang/String;
   8:   invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11:  pop
   12:  aload_0
   13:  getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   16:  aload_0
   17:  getfield    #3; //Field a:Ljava/lang/String;
   20:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   23:  pop
   24:  return

}

Мы можем видеть 2 вещи.

Во-первых, метод normal использует один и тот же экземпляр String для обоих этих вызовов (в действительности это тот же литерал, который установлен для переменной-члена a этого классав блоке инициализации)

А во-вторых, метод clever длиннее, чем normal.Это связано с тем, что для извлечения свойства из класса требуются дополнительные шаги.

Итак, мораль этой истории в том, что в 99% случаев Java делает все правильно, самостоятельно, и в этом нет необходимости.в попытке быть умным ;-) (а javap - действительно классный инструмент, когда вы хотите точно знать, что происходит)

...