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

== оператор со строками

Приведенный ниже код не должен печатать "Bye", так как оператор == используется для сравнения ссылок, но, как ни странно, "Bye" все еще печатается. Почему это происходит? Я использую Netbeans 6.9.1 в качестве среды IDE.

public class Test {
    public static void main(String [] args) {
        String test ="Hi";
        if(test=="Hi"){
            System.out.println("Bye");
        }
    }
}
4b9b3361

Ответ 1

Это поведение происходит из-за интернирования. Поведение описано в документах для String#intern (в том числе, почему оно появляется в вашем коде, даже если вы никогда не вызываете String#intern):

Пул строк, первоначально пустой, поддерживается в частном порядке классом String.

Когда вызывается метод intern, если пул уже содержит строку, равную этому объекту String, как определено методом equals(Object), тогда возвращается строка из пула. В противном случае этот объект String добавляется в пул и возвращается ссылка на этот объект String.

Из этого следует, что для любых двух строк s и t, s.intern() == t.intern() есть true тогда и только тогда, когда s.equals(t) истинно.

Все литералы и строковые константные выражения интернированы. Строковые литералы определены в §3.10.5 спецификации Java Language Specification.

Итак, например:

public class Test {

    private String s1 = "Hi";

    public static void main(String [] args) {

        new Test().test();
        System.exit(0);
    }

    public void test() {
        String s2 ="Hi";
        String s3;

        System.out.println("[statics]          s2 == s1? " + (s2 == s1));
        s3 = "H" + part2();
        System.out.println("[before interning] s3 == s1? " + (s3 == s1));
        s3 = s3.intern();
        System.out.println("[after interning]  s3 == s1? " + (s3 == s1));
        System.exit(0);
    }

    protected String part2() {
        return "i";
    }
}

Вывод:

[statics]          s2 == s1? true
[before interning] s3 == s1? false
[after interning]  s3 == s1? true

Пройдя через это:

  • Литерал, назначенный s1, автоматически интернирован, поэтому s1 заканчивается ссылкой на строку в пуле.
  • Литеральный, назначенный s2, также автоинтерминирован, и поэтому s2 заканчивается, указывая на тот же экземпляр s1, на который указывает. Это прекрасно, даже если два бита кода могут быть полностью неизвестны друг другу, потому что экземпляры Java String неизменяемы. Вы не можете их изменить. Вы можете использовать такие методы, как toLowerCase, чтобы вернуть новую строку с изменениями, но исходный текст, который вы назвали toLowerCase (и т.д.), Остается неизменным. Таким образом, они могут безопасно делиться между несвязанным кодом.
  • Мы создаем новый экземпляр String через операцию выполнения. Хотя новый экземпляр имеет ту же последовательность символов, что и интернированный, это отдельный экземпляр. Среда выполнения не создает динамически создаваемые строки автоматически, потому что есть затраты: работа по поиску строки в пуле. (В то время как при компиляции компилятор может взять эту стоимость на себя.) Итак, теперь у нас есть два экземпляра: один s1 и s2 указывают на, а один s3 указывает на. Таким образом, код показывает, что s3 != s1.
  • Затем мы явно ставим s3. Возможно, это большая строка, которую мы планируем долго удерживать, и мы считаем, что она будет дублироваться в других местах. Поэтому мы принимаем работу по интернированию в обмен на потенциальную экономию памяти. Поскольку интернирование по определению означает, что мы можем вернуть новую ссылку, мы возвращаем результат обратно на s3.
  • И мы можем видеть, что действительно, s3 теперь указывает на тот же экземпляр s1 и s2 на.

Ответ 2

Жесткокодированные строки компилируются в таблицу строк JVM, в которой содержатся уникальные строки - это компилятор хранит только одну копию "Привет", поэтому вы сравниваете этот же объект, поэтому == работает.

Если вы на самом деле создаете новую String с помощью конструктора, например новый String("Hi"), вы получите другой объект.

Ответ 3

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

Ответ 4

Основная причина этого в том, что "Hi" выбирается из String Pool. У неизменяемого объекта должен быть какой-то кеш, чтобы он мог работать лучше. Таким образом, класс String является неизменным и использует String Pool для базового кэша.

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