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

Связано с интернетом String

public static void main(String[] args) {

    String a = new String("lo").intern();
    final String d = a.intern();
    String b = "lo";
    final String e = "lo";
    String c = "Hello";
    System.out.println(b==a);//true
    System.out.println(d==a);//true
    System.out.println(e==a);//true
    System.out.println(c=="Hel"+a); //why is this false? when e==a is true
    System.out.println(c=="Hel"+d); //why is this false?
    System.out.println(c=="Hel"+b); //why is this false?
    System.out.println(c=="Hel"+e); //this is true

}

В результате получается

true
true
true
false
false
false
true

Выражение e==a истинно, подразумевает ту же ссылку. Итак, почему последнее выражение истинно, но четвертое - последнее, т.е. c== "Hel"+a - false?

4b9b3361

Ответ 1

Выражение

"Hel" + a

Не является постоянной времени компиляции. Собственно, он компилируется в:

new StringBuilder().append("Hel").append(a).toString()

(или аналогичный), который создает новый объект String во время выполнения.

Однако, поскольку e является окончательным, компилятор может определить, что конкатенация значений "Hel" и e является постоянным значением и, таким образом, ставляет его.

Ответ 2

все эти строки вычисляются во время выполнения, поэтому они различаются

System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?

этот вычисляется во время компиляции, так как e является окончательным:

System.out.println(c=="Hel"+e); //this is true

если вы измените код на это:

    System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
    System.out.println(c==("Hel"+d).intern()); //why is this false?
    System.out.println(c==("Hel"+b).intern()); //why is this false?

все они будут выдавать true

Ответ 3

Компилятор Java (javac) переводит ваш код в Java в байтовый код, который выполняется JVM. Он также выполняет некоторые оптимизации для вас. Вы можете проверить сгенерированный байт-код с помощью утилиты javap с параметром -c

Конкатенация с окончательной строкой

c==a истинно, потому что c - final Вот код байта для этого фрагмента (только последнее сравнение):

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String Hello
   2:   astore_2
   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   aload_2
   7:   ldc     #2; //String Hello
   9:   if_acmpne       16
   12:  iconst_1
   13:  goto    17
   16:  iconst_0
   17:  invokevirtual   #4; //Method java/io/PrintStream.println:(Z)V
   20:  return

}

Как вы видите, компилятор java объединил "Hel" с "lo" и просто сравнил два строковых словаря "Hello". Java ставит строковые литералы по умолчанию - почему он возвращает true

Конкатенация с нестрочной строкой

Если вы объединяете строковый литерал с нестрочной переменной String, код байта будет отличаться:

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String lo
   2:   astore_1
   3:   ldc     #3; //String Hello
   5:   astore_2
   6:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   9:   aload_2
   10:  new     #5; //class java/lang/StringBuilder
   13:  dup
   14:  invokespecial   #6; //Method java/lang/StringBuilder."<init>":()V
   17:  ldc     #7; //String Hel
   19:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:  aload_1
   23:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   26:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   29:  if_acmpne       36
   32:  iconst_1
   33:  goto    37
   36:  iconst_0
   37:  invokevirtual   #10; //Method java/io/PrintStream.println:(Z)V
   40:  return

}

Здесь мы сравниваем результат метода java/lang/StringBuilder.toString:()Ljava/lang/String;, который явно возвращает другой объект - он равен "Hello" по значению, но не по ссылке

Более подробную информацию о сравнении строк в этом fooobar.com/questions/21/...

Ответ 4

Даже если вы используете метод intern(), вы должны помнить, что == сравнивается по ссылке, а не по значению.

Итак, в случаях

System.out.println(c=="Hel"+a);
    System.out.println(c=="Hel"+d); 
    System.out.println(c=="Hel"+b); 

"Hel" + a или "Hel" + d или "Hel" + b будет иметь новую ссылку в памяти, которая не равна значению c.

в последнем случае, поскольку строковое значение является окончательным, оценка выполняется во время компиляции, а не во время выполнения, поскольку она никогда не изменится. Также, если вы думаете, когда вы определяете строковый литерал, Java внутренне ставит их в очередь.