о строке а = "привет";Строка b = "привет" a == b, в Java - PullRequest
2 голосов
/ 26 июня 2011

проверьте следующую программу: Запустите ее на хосте java sun java, все будет "true".

-------- обновлено: получил ответ от Стивена и Дани, изменил программучтобы добавить метод строки intern -----------

как это будет, если B будет отдельно скомпилирован не вместе с A, что произойдет ??? например, B скомпилировани вставьте jar, и поместите его путь к классу при запуске TestStringEqual ??

Кроме того, определена ли эта оптимизация времени компиляции Java, или оптимизация времени выполнения Java, или спецификация языка Java ??

Кроме того, эта программа дает один и тот же результат на разных виртуальных машинах или только одну функцию виртуальной машины?

спасибо

public class TestStringEqual {
public static String HELLO = "hello";

private String m_hello;

public TestStringEqual() {
    m_hello = "hello";
}

public static void main(String[] args) {
    String a = "hello";
    String b = "hello";

    System.out.println("string a== string b:" + (a == b));

    System.out.println("static memebr ==a:" + (HELLO == a));

    System.out.println("instance field ==a:"
            + (new TestStringEqual().getHello() == a));

    System.out.println("hello in B ==a:" + (B.B_HELLO == a));

    System.out.println("interned new string object in heep==a:"
            + ( new String("hello").intern() == a));

}

public String getHello() {
    return this.m_hello;
}
}
class B{
public static final String B_HELLO = "he"+"llo";
}

Ответы [ 6 ]

3 голосов
/ 26 июня 2011

В этом нет никакой тайны. Вам просто нужно знать три основных факта о Java:

  • Оператор '==' для ссылок на объекты проверяет, совпадают ли две ссылки на объекты; т.е. если они указывают на один и тот же объект. Ссылка JLS 15.21.3

  • Все строки литералы с одинаковой последовательностью символов в программе Java будут представлены одним и тем же объектом String. Ссылка JLS 3.10.5 Так (например) "hello" == "hello" сравнивает один и тот же объект.

  • Выражения констант оцениваются во время компиляции. Ссылка JLS 15,28 . Так (например) "hell" + "o" вычисляется во время компиляции и поэтому эквивалентно литералу "hello".

Эти три факта изложены в Спецификациях языка Java. Их достаточно, чтобы объяснить «загадочные» аспекты поведения вашей программы, не полагаясь ни на что другое.

Более подробное объяснение, включающее пул строк, строковые литералы, интернированные загрузчиком классов, байт-коды, испускаемые компилятором, и т. Д. И т. Д., - просто детали реализации . Вам не нужно , нужно , чтобы понять эти детали, если вы понимаете, что говорит JLS, и они действительно не помогают сделать JLS более понятным (IMO).


Примечания:

  1. Определение того, что является, а что не является константным выражением, является немного сложным. Некоторые вещи, которые вы можете себе представить как постоянные, на самом деле не являются таковыми. Например, "hello".length() не является константным выражением. Однако конкатенация двух строковых литералов является константным выражением.

  2. В объяснении равенства строковых литералов в JLS фактически упоминается интернирование как механизм , с помощью которого реализуется это свойство литералов.

3 голосов
/ 26 июня 2011

На уровне JVM инструкция LDC (постоянная загрузки) используется для помещения строкового литерала в стек. По соображениям производительности строковый литерал не хранится в самом коде; он хранится в постоянном пуле класса. Пул констант - это таблица, которая появляется в начале файла класса, содержащего строковые литералы, числовые литералы, дескрипторы полей и методов и некоторые другие вещи. LDC сопровождается байтом, определяющим индекс строки в пуле констант. (Если один байт недостаточно велик, компилятор будет использовать LDC_W, за которым следует 16-разрядное смещение. Отсюда ограничение в 65 536 констант.)

Если один и тот же строковый литерал встречается дважды в одном и том же классе, javac достаточно умен, чтобы создать только одну запись в постоянном пуле. Когда класс загружен, JVM создает фактические объекты String из данных в постоянном пуле. LDC s, которые содержат одинаковое смещение в пуле констант, таким образом, приведет к тому, что одна и та же строка будет помещена в стек. Такие инструкции, как IF_ACMPEQ (который проверяет равенство ссылок, как ==), распознают строки как идентичные.

См. JVMS для получения дополнительной информации.

1 голос
/ 26 июня 2011

Поможет ли эта ссылка - Вопросы о пуле строк Java ?.

1 голос
/ 26 июня 2011

Это неизменяемая строка (не может быть изменена или изменена), а не иммунная, хотя я полагаю, вы можете утверждать, что она не подвержена изменениям: -)

Это означает, что вы не можете изменить саму базовую строку, вы можете только присвоить переменной другую строку. Итак:

string a = "Hello";
a = "Goodbye";

не изменяет память, в которой хранится "Hello", оно меняет a, указывая на другое место в памяти, где хранится "Goodbye".

Это позволяет Java обмениваться строками для повышения эффективности. Вы даже можете получить случаи, когда строки, такие как "deoxyribonucleic acid" и "acid", могут совместно использовать пространство, где последние указывают на определенное место в первом. Опять же, это стало возможным благодаря неизменности таких строк.

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

0 голосов
/ 26 июня 2011

Что касается a==b, кажется, что компилятор делает ярлыки и использует один и тот же строковый объект. Когда я объявляю свои переменные следующим образом, я получаю a==b is false.

String a = "hello";
String b = "hell";
String temp = "o";
if (new java.util.Random().nextDouble() < 0.5) b += temp;
else b += "o";

Если я сделаю String b = "hell"+"o";, я все равно получу a==b как true.

0 голосов
/ 26 июня 2011

Это довольно просто: компилятор сгенерирует (байт-код) константу для строки "hello" при первом обнаружении.В обычном ассемблере это будет в разделе .TEXT.

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

Вероятно, это не будет работать при вводе, т. Е. Если вы позволите пользовательскому вводу "привет"и == - сравните это со строками приветствия во время компиляции, которые вы, скорее всего, получите false.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...