2013-05-24 2 views
30

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

Я могу понять, что строка 1, строка 2 и строка 3 являются true, но почему строка ?

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

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, но это не объясняет четко.

Буду признателен за полное объяснение.

+7

+1 для любопытства .. хороший первый вопрос – sanbhat

+4

Поскольку равенство hashcode не подразумевает идентичность объекта. См. Javadoc для 'Object.hashCode(). – EJP

+0

Если бы вы знали это, вы бы не вызвали сценарий Resonance Cascade! – Alex

ответ

25

Каждый compile-time constant expression, который имеет тип String, будет помещен в пул строк.

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

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

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

Хэш-коды являются одинаковыми, поскольку the hashCode of a String depends only on its content. Это требуется по договору equals() и hashCode().

+0

ok Я хочу, чтобы очистить еще одну вещь, если мы делаем, как «Hello» в программе или в условии if, thats новый объект или литерал ?? –

+1

Литерал, такой как '' Hello '', всегда является выражением постоянной времени компиляции, поэтому это будет взято из пула констант. –

+0

ОК, это нормально, скажем, если вопрос состоит в том, сколько объектов сформировано, тогда я делаю if (hello == «Hello»), поэтому, когда я набираю «Hello», это не объект и компиляционный литерал времени и сохраняются в бассейне, не так ли? –

0

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

Вы можете проверить эту ссылку pooling concept

+2

тогда как это применимо для hello == («Hel» + «lo») -> true? – sanbhat

+0

Не могли бы вы углубиться. Я не уверен, что вы прав – Craig

+0

ok в строке3 Я делаю манипуляции «Hel» + «lo» создаст новый объект, но он все еще ссылается на «Hello» String в пуле и когда «Hel» + lo, lo - строковая переменная добавляется, он создаст «Привет», тогда почему это не относится к одному литералу пула? –

0

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

("Hel"+lo)) + " " 

переводится внутренне

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

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

+1

Затем как (hello == ("Hel" + "lo")) + "" -> true? :-) Даже здесь добавлена ​​дополнительная строка – sanbhat

+0

неправильная "" не добавляется, я проверяю перед конкатенацией, вижу брекеты –

+0

@sanbhat Я согласен – Saurabh

1

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

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

+0

stackoverflow.com/questions/3029244/are-strings-created-with-concatenation-stored-in-the-string-pool тоже написано здесь –

0

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

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

+0

хм неплохо, поэтому во время компиляции он проверяет пул строк, но когда дело доходит до строки манипуляции с lo, он будет проверять во время выполнения, тогда String hello = «Hello» также должен быть проверен во время выполнения, правильно? –

+0

String hello = «Hello» будет выполняться во время компиляции, потому что компилятор знает, перед выполнением любого кода, значение («Hello»), которое должно войти в эту строку. – Ren

2

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

здесь ссылка следующим образом: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5

+0

, который проигнорировал этот комментарий, я думаю, что это правильно, @JoachimSauer, пожалуйста, проверьте! –

+0

ОК, вот прямая ссылка на страницу в книге. – Chechulin

0

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

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

0

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

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

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

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

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

+0

Хм, я понял, это беспорядок со Струнами! –

1

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

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.

0

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

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 .

В результате ложно, если операнды различных строковых объектов, даже если они содержат ту же самую последовательность символов (§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 
    } 
} 

Высказывание ("Хель" + Л) в строке 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 

Потому что,

"Здравствуй" объект в этом заявлении:

String hello = "Hello"; 

и ("Хель" + с) объект в этом заявлении:

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

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

* они оба содержат один и тот же характер, последовательность, которая является «Hello ».

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

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

0

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

+0

'String' переопределяет реализацию' Object' 'hashCode'. – mkl

+0

Полностью верный, хэш-код для String вычисляется значением. – Monster

Смежные вопросы