Java == для объектов String перестало работать?

  public class Comparison {
        public static void main(String[] args) {
            String s = "prova";
            String s2 = "prova";
            System.out.println(s == s2);
            System.out.println(s.equals(s2));
        }
    }

выходы:

true
true

на моей машине. Зачем? Не должно быть == сравнивать ссылки на объекты равенства?

Ответ 1

Поскольку экземпляры String являются неизменяемыми, язык Java способен сделать некоторые оптимизации, в соответствии с которыми String литералы (или, более общо, String, значения которых константы времени компиляции) интернированы и фактически ссылаются на один и тот же объект (т.е. ==).

JLS 3.10.5 Строковые литералы

Каждый строковый литерал является ссылкой на экземпляр class String. Объекты String имеют постоянное значение. Строковые литералы или, в более общем смысле, строки, которые являются значениями константных выражений, "интернированы", чтобы обмениваться уникальными экземплярами, используя метод String.intern.

Вот почему вы получаете следующее:

System.out.println("yes" == "yes"); // true
System.out.println(99 + "bottles" == "99bottles"); // true
System.out.println("7" + "11" == "" + '7' + '1' + (char) (50-1)); // true
System.out.println("trueLove" == (true + "Love")); // true
System.out.println("MGD64" == "MGD" + Long.SIZE);

Сказано, что нужно сказать, что вы не должны полагаться на сравнение == для String в целом и должны использовать equals для не null instanceof String. В частности, не испытывайте соблазна intern() всего вашего String, чтобы вы могли использовать ==, не зная, как работает интернирование строк.

Связанные вопросы


Вкл new String(...)

Если по какой-то неподдельной причине вам нужно создать два объекта String (которые по определению не являются ==), но еще equals, то вы можете, среди прочего, использовать этот конструктор:

public String(String original): Инициализирует вновь созданный объект String, чтобы он представлял ту же последовательность символов, что и аргумент; Другими словами, вновь созданная строка является копией строки аргумента. Если явная копия оригинала не нужна, использование этого конструктора не нужно, так как Strings являются неизменяемыми.

Таким образом, вы можете:

System.out.println("x" == new String("x")); // false

Оператор new всегда создает новый объект, поэтому гарантированно печать false. Тем не менее, это обычно не то, что вам действительно нужно делать. По возможности вы должны просто использовать строковые литералы вместо явного создания new String для него.

Связанные вопросы

Ответ 2

JLS, 3.10.5 = > Гарантируется, что литеральный строковый объект будет повторно использоваться любым другим кодом, работающим в той же виртуальной машина, которая содержит один и тот же строковый литерал

Ответ 3

Если вы явно создаете новые объекты, == возвращает false:

String s1 = new String("prova");
String s2 = new String("prova");
System.out.println(s1 == s2); // returns false.

В противном случае JVM может использовать один и тот же объект, поэтому s1 == s2 вернет true.

Ответ 4

Это так. Но литералы String объединены, поэтому "prova" возвращает тот же экземпляр.

Ответ 5

String s = "prova";
String s2 = "prova";

s и s2 являются буквальными строками, которые указывают один и тот же объект в String Pool JVM, так что сравнение возвращает true.

Ответ 6

Да, "prova" хранится в двоичном пуле java, поэтому его та же ссылка.

Ответ 7

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

Ответ 8

JVM может оптимизировать использование String, чтобы в памяти был только один экземпляр "равной" строки. В этом случае оператор == возвращает true. Но не рассчитывайте на это.

Ответ 9

Вы должны понимать, что "==" сравнивает ссылки, а "equals" сравнивает значения. Оба s и s1 указывают на один и тот же строковый литерал, поэтому их ссылки одинаковы.

Ответ 10

Когда вы помещаете литеральную строку в код Java, строка автоматически интернирована компилятором, то есть создается один статический глобальный экземпляр. Или, более конкретно, он помещается в таблицу интернированных строк. Любая другая цитированная строка, которая точно такая же, по содержанию, будет ссылаться на одну и ту же интернированную строку.

Итак, в вашем коде s и s2 есть ту же строку

Ответ 11

В идеале этого никогда не должно быть. Потому что спецификация java гарантирует это. Поэтому я думаю, что это может быть ошибка в JVM, вы должны сообщать о солнечных микросистемах.