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

Поведение струнных литералов сбивает с толку

Поведение строковых литералов очень сбивает с толку в коде ниже.

Я понимаю строку 1, строку 2 и строку 3 true, но почему строка 4 false?

Когда я печатаю хэш-код, оба они одинаковы.

class Hello
{
   public static void main(String[] args)
   {
      String hello = "Hello", lo = "lo";
      System.out.print((Other1.hello == hello) + " ");     //line 1
      System.out.print((Other1.hello == "Hello") + " ");   //line 2
      System.out.print((hello == ("Hel"+"lo")) + " ");       //line 3
      System.out.print((hello == ("Hel"+lo)) + " ");         //line 4
      System.out.println(hello == ("Hel"+lo).intern());      //line 5
      System.out.println(("Hel"+lo).hashCode());   //hashcode is 69609650 (machine depedent)
      System.out.println("Hello".hashCode());       //hashcode is same WHY ??.
   }
}

class Other1 { static String hello = "Hello"; }

Я знаю, что == проверяет ссылочное равенство и проверяет пул на литералы. Я знаю, что equals() - правильный путь. Я хочу понять концепцию.

Я уже проверил этот question, но он не объясняет четко.

Я был бы признателен за полное объяснение.

4b9b3361

Ответ 1

Каждое выражение константы времени компиляции, которое имеет тип String, будет помещено в пул строк.

По сути, это означает: если компилятор может (легко) "вычислить" значение String без запуска программы, то он будет помещен в пул (правила немного сложнее, чем это, и имеют несколько угловые случаи, см. ссылку выше для всех деталей).

Это верно для всех строк в строках 1-3.

"Hel"+lo не является выражением константы времени компиляции, потому что lo является непостоянной переменной.

Хэш-коды одинаковы, потому что hashCode строки зависит только от его содержимого. Это требуется по контракту equals() и hashCode().

Ответ 3

Это потому, что компилятор в этом экземпляре недостаточно умен, чтобы понять, что он может записывать в том же строчном литерале.

Hashcode должен всегда возвращать одно и то же значение для эквивалентных строк (вызов .equals на нем возвращает true), поэтому возвращает тот же результат.

Ответ 4

Объект String может быть создан следующими способами:

String str = new String("abcd");  // Using the new operator 
                                  // str is assigned with "abcd" value at compile time.

String str="abcd";         // Using string literal
                           // str is assigned with "abcd" value at compile time.

String str="ab" + "cd";    // Using string constant expression.
                           // str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1;    // Using string expression.
                           // str is assigned with "abcd" value at run time only.

и Hashcode будет вычисляться только во время выполнения на основе содержимого объектов String.

Ответ 5

Как вы уже знаете... это просто из-за ссылки... когда строка исходит из пула, она будет иметь такое же refrence... но когда вы делаете manuplations, создается новая строка с новым refrence...

Вы можете проверить эту ссылку для концепции объединения

Ответ 6

Это потому, что следующий код

("Hel"+lo)) + " "

внутренне переведено на

new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()

Итак, вы можете видеть, что полностью новый экземпляр String создается с помощью разных экземпляров String. Вот почему вы получаете false, поскольку указывают на разные ячейки памяти в куче

Ответ 7

Хэш-код не имеет ничего общего с ссылкой на объекты (проверка == - это ссылочный компаратор). Его возможно иметь 2 объекта, где hashCode возвращает одно и то же значение, оператор equals возвращает true, но == возвращает false. Это когда они представляют собой два разных объекта, но с одинаковым значением.

Я считаю, что причина, по которой строка 4 возвращает false, заключается в том, что это значение, вычисленное во время выполнения, и, таким образом, это другой экземпляр строки с другой ссылкой.

Ответ 8

Строковые литералы сохраняются в специальной памяти, если они точно совпадают, они указываются на одну и ту же карту памяти. Если вы не создадите литерал String, будет создан новый объект, чтобы он не указывал на эту память, поэтому ссылка не будет одинаковой.

Метод intern() сообщает виртуальной машине помещать ее в эту общую, строчную литералную карту памяти, поэтому в следующий раз, когда вы сделаете этот литерал, он будет искать там и указывать на нее.

Ответ 9

Разница между строками 3 и 4 выглядит следующим образом.

• Строки, вычисленные постоянными выражениями, вычисляются во время компиляции, а затем обрабатываются так, как если бы они были литералами.

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

Вышеупомянутая ссылка взята из спецификации java. Пожалуйста, дайте мне знать, если вам нужно больше разъяснений.

http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5

Ответ 10

Наконец, я знаю ответ!

Read Java SE 8 спецификации раздел 15.21.3 равенство ссылок Операторы == и!= (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3)

В то время как == может использоваться для сравнения ссылок типа String, такой тест равенства определяет, ссылаются ли два операнда на тот же объект String.

Результат false, если операнды разныеСтроковые объекты, , даже если они содержат одну и ту же последовательность символов (§3.10.5). Содержимое двух строк s и t можно проверить на равенство вызовом метода s.equals(t).

Итак, следующий код:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

Операторы ( "Hel" + lo) в строке 3 возвращают новые строки, которые вычисляются путем конкатенации в время выполнения.

* Строки, вычисленные путем конкатенации в время выполнения, создаются и поэтому различны. (http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634)

Итак, результат этого кода:

class Test {
    public static void main(String[] args) {
        String hello = "Hello";
        String lo = "lo";
        System.out.println((hello == ("Hel"+lo))); // line 3
    }
}

:

false

Поскольку,

объект Hello в этом выражении:

String hello = "Hello";

и ( "Hel" + lo) в этом выражении:

System.out.print((hello == ("Hel"+lo)) + " ");

отличается, хотя:

* оба они содержат один и тот же символ последовательности, который является "Hello".

* оба они имеют одинаковый хэш-код.

* hello.equals(( "Hel" + lo)) вернет true.

Ответ 11

System.identityHashCode() будет возвращен методом по умолчанию hashCode(), это обычно реализуется путем преобразования внутреннего адреса объекта в целое число.