Кто-нибудь, пожалуйста, ответьте на это. String a = "Java"; String b = "Java"; System.out.println (a == b); true // но System.out.println ("a == b?" + a == b); // ложь ...
Энергия
я не понимаю, когда я добавил какой-то комментарий ("a == b?) => мой результат становится ЛОЖНЫМ. почему?
Energy
@Energy Результатом является то, falseчто порядок операций диктует, что оператор + идет первым, объединяя "a == b?" с, чтобы создать строку "a == b? Java". Тогда выражение "a==b?Java" == bоценивается как ложное.
Эллисон Б
@AllisonB получил это, спасибо большое!
Энергия
Ответы:
187
new String("text");
явно создает новый и референциально отличный экземпляр Stringобъекта; String s = "text";может повторно использовать экземпляр из пула строковых констант, если он доступен.
Вы очень редко бы хотели использовать new String(anotherString)конструктор. Из API:
String(String original): Инициализирует вновь созданныйString объект, чтобы он представлял ту же последовательность символов, что и аргумент; другими словами, вновь созданная строка является копией строки аргумента. Если не требуется явная копия оригинала, использование этого конструктора не требуется, поскольку строки являются неизменяемыми.
==на двух ссылочных типах есть сравнение ссылочной идентичности. Два объекта, equalsкоторые не обязательно ==. Обычно неправильно использовать ==ссылочные типы; большую часть времени equalsнужно использовать вместо этого.
Тем не менее, если по какой-либо причине вам нужно создать две строки, equalsно не ==строку, вы можете использовать new String(anotherString)конструктор. Однако нужно еще раз сказать, что это очень своеобразно и редко является намерением.
Если я напишу: String s = new String ("abc"); А теперь я пишу: String s = "abc"; Will String s = "abc"; создать новый строковый литерал в пуле строк?
Kaveesh Kanwal
Почему никто не отвечает на предыдущий вопрос?
Зедс
2
@KaveeshKanwal Нет, литерал не будет дублироваться. Как видите, есть 2 "abc"с. Только один из них пойдет в пул String, а другой будет ссылаться на него. Тогда есть то, sчто будет правильным новым объектом.
Каяман
1
@Kaveesh Kanwal - String s = new String ("abc") будет создавать только новый объект String со значением "abc". И 2-й оператор проверит, присутствует ли какой-либо строковый литерал abc в String Pool или нет. Если он уже присутствует, возвращается ссылка на существующий, а если нет, то в пуле String создается новый литерал ("abc"). Надеюсь, это решит ваш запрос!
user968813
В этом нет «мая». Компилятор должен объединять строковые литералы. JLS 3.10.5 .
Маркиз Лорн
119
Строковые литералы войдут в String Constant Pool .
Приведенный ниже снимок может помочь вам понять это визуально, чтобы запомнить его на более длительное время.
Создание объекта построчно:
String str1 =newString("java5");
Используя строковый литерал "java5" в конструкторе, новое строковое значение сохраняется в пуле строковых констант. Используя оператор new, в куче создается новый строковый объект со значением «java5».
String str2 ="java5"
Ссылка "str2" указывает на уже сохраненное значение в пуле строковых констант
String str3 =newString(str2);
В куче создается новый строковый объект с тем же значением, что и у ссылки "str2"
String str4 ="java5";
Ссылка "str4" указывает на уже сохраненное значение в пуле строковых констант
Хороший ответ ... но хотелось бы знать, что теперь я собираюсь изменить значение str1 = "java6", тогда это изменит значение str4?
CoronaPintu
2
да, я проверил, это не изменит значение str4
CoronaPintu
@Braj Можете ли вы предоставить документацию с утверждением вашего Ответчика?
Василий Бурк
@Braj: Заголовки для «Кучи» и «пула» в таблице должны быть обратными?
Рахул Куруп
Не верно. Постоянный пул создается во время компиляции, а не во время выполнения. Не используйте форматирование цитаты для текста, который не цитируется.
другой создает строку в константе pool ( "text"), а другую - в обычном пространстве кучи ( s). Обе строки будут иметь одинаковое значение «text».
String s =newString("text");
s затем теряется (имеет право на GC), если впоследствии не используется.
Строковые литералы, с другой стороны, используются повторно. Если вы используете "text"в нескольких местах вашего класса, на самом деле это будет одна и только одна строка (т.е. несколько ссылок на одну и ту же строку в пуле).
Более того, строковый литерал всегда ссылается на один и тот же экземпляр класса String. Это связано с тем, что строковые литералы - или, в более общем смысле, строки, являющиеся значениями константных выражений (§15.28) - «интернированы», чтобы обмениваться уникальными экземплярами, используя метод String.intern.
Строковый литерал является ссылкой на экземпляр класса String и является производным от структуры CONSTANT_String_info (§4.4.3) в двоичном представлении класса или интерфейса. Структура CONSTANT_String_info дает последовательность кодовых точек Unicode, составляющих строковый литерал.
Язык программирования Java требует, чтобы идентичные строковые литералы (то есть литералы, которые содержат одинаковую последовательность кодовых точек) должны ссылаться на один и тот же экземпляр класса String (JLS §3.10.5). Кроме того, если метод String.intern вызывается для какой-либо строки, результатом является ссылка на тот же экземпляр класса, который будет возвращен, если эта строка появится в виде литерала. Таким образом, следующее выражение должно иметь значение true:
("a"+"b"+"c").intern()=="abc"
Для получения строкового литерала виртуальная машина Java проверяет последовательность кодовых точек, заданных структурой CONSTANT_String_info.
Если метод String.intern ранее вызывался для экземпляра класса String, содержащего последовательность кодовых точек Unicode, идентичную той, которая задана структурой CONSTANT_String_info, то результатом строкового литерального вывода является ссылка на тот же экземпляр класса String.
В противном случае создается новый экземпляр класса String, содержащий последовательность кодовых точек Unicode, заданную структурой CONSTANT_String_info; ссылка на этот экземпляр класса является результатом строкового литерала. Наконец, метод intern нового экземпляра String вызывается.
Bytecode
Также полезно взглянуть на реализацию байт-кода в OpenJDK 7.
Если мы декомпилируем:
publicclassStringPool{publicstaticvoid main(String[] args){String a ="abc";String b ="abc";String c =newString("abc");System.out.println(a);System.out.println(b);System.out.println(a == c);}}
str1не участвует в стоимости str2или str3или str4каким-либо образом.
Маркиз Лорн
1
Думайте о "bla"том, чтобы быть волшебной фабрикой как Strings.createString("bla")(псевдо). Фабрика содержит пул всех строк, созданных таким образом.
Если он вызывается, он проверяет, есть ли уже строка в пуле с этим значением. Если true, он возвращает этот строковый объект, следовательно, строки, полученные таким образом, действительно являются одним и тем же объектом.
Если нет, то он создает новый строковый объект внутри, сохраняет его в пуле и затем возвращает его. Таким образом, когда то же самое строковое значение запрашивается в следующий раз, оно возвращает тот же экземпляр.
Создание вручную new String("")переопределяет это поведение, обходя пул строковых литералов. Таким образом, всегда следует проверять равенство, используя equals()который сравнивает последовательность символов вместо равенства объектов.
«Волшебная фабрика», на которую вы ссылаетесь, - это не что иное, как компилятор Java. Ошибочно писать об этом процессе, как если бы он происходил во время выполнения.
Маркиз Лорн
1
Один простой способ понять разницу ниже:
String s ="abc";String s1="abc";String s2=newString("abc");if(s==s1){System.out.println("s==s1 is true");}else{System.out.println("s==s1 is false");}if(s==s2){System.out.println("s==s2 is true");}else{System.out.println("s==s2 is false");}
вывод
s==s1 is true
s==s2 is false
Таким образом, new String () всегда будет создавать новый экземпляр.
Любой строковый литерал создается внутри пула строковых литералов, и пул не допускает дублирования. Таким образом, если два или более строковых объекта инициализируются одним и тем же литеральным значением, тогда все объекты будут указывать на один и тот же литерал.
String obj1 ="abc";String obj2 ="abc";
«obj1» и «obj2» будут указывать на один и тот же строковый литерал, а пул строкового литерала будет иметь только один литерал «abc».
Когда мы создаем объект класса String с использованием нового ключевого слова, созданная таким образом строка сохраняется в памяти кучи. Любой строковый литерал, переданный в качестве параметра конструктору класса String, однако, сохраняется в пуле строк. Если мы создадим несколько объектов, используя одно и то же значение с оператором new, новый объект будет создаваться в куче каждый раз, потому что этого нового оператора следует избегать.
«obj1» и «obj2» будут указывать на два разных объекта в куче, а пул строкового литерала будет иметь только один литерал «abc».
Также следует отметить, что в отношении поведения строк следует отметить, что любое новое присваивание или конкатенация, выполняемая со строкой, создает новый объект в памяти.
Теперь в приведенном выше случае:
строка 1: литерал «abc» хранится в пуле строк.
Строка 2: литерал «abcdef» сохраняется в пуле строк.
Строка 3: новый литерал «xyz» сохраняется в пуле строк, и «str1» начинает указывать на этот литерал.
Строка 4: поскольку значение генерируется путем добавления к другой переменной, результат сохраняется в памяти кучи, а добавляемый литерал «ghi» будет проверен на наличие в пуле строк и будет создан, так как он не существует в вышеуказанный случай.
Хотя это выглядит одинаково с точки зрения программистов, оно оказывает большое влияние на производительность. Вы хотели бы использовать первую форму почти всегда.
Он проверит, содержит ли пул констант String строку "hello"? Если он присутствует, он не будет добавлять запись в пул констант String. Если нет, то он добавит запись в пул констант String.
Объект будет создан в области памяти кучи и str ссылки будут ссылаться на объект, созданный в области динамической памяти.
если вам нужна strссылка на точечный объект, содержащийся в пуле констант String, нужно явно вызватьstr.intern();
String str ="world";
Он проверит, содержит ли пул констант String строку "hello"? Если он присутствует, он не будет добавлять запись в пул констант String. Если нет, то он добавит запись в пул констант String.
В обоих вышеупомянутых случаях strссылки на String "world"присутствуют в пуле констант.
Это компилятор Java. Строковый литерал создает уникальную запись в пуле констант во время компиляции. Ошибочно деактивировать этот процесс, как если бы он происходил во время выполнения ...
Маркиз Лорн,
Можете ли вы объяснить, что не так в этом посте ясно?
Джаеш
Что неправильно в этом посте, так это то, что строковый литерал объединяется во время компиляции, как я уже сказал. Не при выполнении кода, как в вашем ответе.
маркиз Лорн
@EJP Я ценю ваш ответ. Можете ли вы указать точную строку, которая является неправильной в ответе. Я вижу, что все ответы выше совпадают с тем, что я написал. Пожалуйста, помогите, я хочу исправить свое понимание. Спасибо.
Джаеш
Вы написали обо всем процессе, как будто все это происходит при выполнении строки кода, что, как я неоднократно говорил вам, не так. Вы не можете свести все это к единственной «точной линии», которая не соответствует вашему ответу.
маркиз Лорн
0
Когда вы храните строку как
String string1 ="Hello";
непосредственно, затем JVM создает объект String с заданной ценой в течение отдельного блока памяти, называемого постоянным пулом String.
И всякий раз, когда мы имеем тенденцию пытаться создать другую строку как
String string2 ="Hello";
JVM проверяет, существует ли какой-либо объект String с постоянной ценой в пуле констант String, если это так, вместо создания нового объекта JVM назначает ссылку на существующий объект новой переменной.
И когда мы храним String как
String string =newString("Hello");
используя ключевое слово new, создается совершенно новый объект с заданной ценой независимо от содержимого пула констант String.
false
что порядок операций диктует, что оператор + идет первым, объединяя "a == b?" с, чтобы создать строку "a == b? Java". Тогда выражение"a==b?Java" == b
оценивается как ложное.Ответы:
new String("text");
явно создает новый и референциально отличный экземплярString
объекта;String s = "text";
может повторно использовать экземпляр из пула строковых констант, если он доступен.Вы очень редко бы хотели использовать
new String(anotherString)
конструктор. Из API:Смежные вопросы
Что означает ссылочное различие
Изучите следующий фрагмент:
==
на двух ссылочных типах есть сравнение ссылочной идентичности. Два объекта,equals
которые не обязательно==
. Обычно неправильно использовать==
ссылочные типы; большую часть времениequals
нужно использовать вместо этого.Тем не менее, если по какой-либо причине вам нужно создать две строки,
equals
но не==
строку, вы можете использоватьnew String(anotherString)
конструктор. Однако нужно еще раз сказать, что это очень своеобразно и редко является намерением.Ссылки
class Object
-boolean Object(equals)
Связанные вопросы
источник
"abc"
с. Только один из них пойдет в пул String, а другой будет ссылаться на него. Тогда есть то,s
что будет правильным новым объектом.Строковые литералы войдут в String Constant Pool .
Приведенный ниже снимок может помочь вам понять это визуально, чтобы запомнить его на более длительное время.
Создание объекта построчно:
Используя строковый литерал "java5" в конструкторе, новое строковое значение сохраняется в пуле строковых констант. Используя оператор new, в куче создается новый строковый объект со значением «java5».
Ссылка "str2" указывает на уже сохраненное значение в пуле строковых констант
В куче создается новый строковый объект с тем же значением, что и у ссылки "str2"
Ссылка "str4" указывает на уже сохраненное значение в пуле строковых констант
Всего объектов: куча - 2, бассейн - 1
Дальнейшее чтение в сообществе Oracle
источник
Создается строка в пуле строковых констант
другой создает строку в константе pool (
"text"
), а другую - в обычном пространстве кучи (s
). Обе строки будут иметь одинаковое значение «text».s
затем теряется (имеет право на GC), если впоследствии не используется.Строковые литералы, с другой стороны, используются повторно. Если вы используете
"text"
в нескольких местах вашего класса, на самом деле это будет одна и только одна строка (т.е. несколько ссылок на одну и ту же строку в пуле).источник
JLS
Концепция называется «интернирование» в JLS.
Соответствующий отрывок из JLS 7 3.10.5 :
JVMs
JVMS 7 5.1 говорит :
Bytecode
Также полезно взглянуть на реализацию байт-кода в OpenJDK 7.
Если мы декомпилируем:
у нас по постоянному пулу:
и
main
:Обратите внимание, как:
0
и3
:ldc #2
загружается одна и та же константа (литералы)12
: создается новый экземпляр строки (с#2
аргументом as)35
:a
иc
сравниваются как обычные объекты сif_acmpne
Представление константных строк довольно волшебно в байт-коде:
new String
)и цитата JVMs выше , кажется, говорят , что всякий раз , когда utf8 указал на то же самое, то идентичные экземпляры загружаются
ldc
.Я сделал аналогичные тесты для полей, и:
static final String s = "abc"
указывает на таблицу констант через атрибут ConstantValueldc
Вывод : есть прямая поддержка байт-кода для пула строк, и представление памяти эффективно.
Бонус: сравните это с целочисленным пулом , который не имеет прямой поддержки байт-кода (т.е. не имеет
CONSTANT_String_info
аналогов).источник
@Braj: я думаю, что вы упомянули об обратном. Пожалуйста, поправьте меня, если я ошибаюсь
Создание объекта построчно:
String str1 = новая строка ("java5")
String str2 = "java5"
String str3 = новая строка (str2)
String str4 = "java5"
источник
str1
не участвует в стоимостиstr2
илиstr3
илиstr4
каким-либо образом.Думайте о
"bla"
том, чтобы быть волшебной фабрикой какStrings.createString("bla")
(псевдо). Фабрика содержит пул всех строк, созданных таким образом.Если он вызывается, он проверяет, есть ли уже строка в пуле с этим значением. Если true, он возвращает этот строковый объект, следовательно, строки, полученные таким образом, действительно являются одним и тем же объектом.
Если нет, то он создает новый строковый объект внутри, сохраняет его в пуле и затем возвращает его. Таким образом, когда то же самое строковое значение запрашивается в следующий раз, оно возвращает тот же экземпляр.
Создание вручную
new String("")
переопределяет это поведение, обходя пул строковых литералов. Таким образом, всегда следует проверять равенство, используяequals()
который сравнивает последовательность символов вместо равенства объектов.источник
Один простой способ понять разницу ниже:
вывод
Таким образом, new String () всегда будет создавать новый экземпляр.
источник
Любой строковый литерал создается внутри пула строковых литералов, и пул не допускает дублирования. Таким образом, если два или более строковых объекта инициализируются одним и тем же литеральным значением, тогда все объекты будут указывать на один и тот же литерал.
«obj1» и «obj2» будут указывать на один и тот же строковый литерал, а пул строкового литерала будет иметь только один литерал «abc».
Когда мы создаем объект класса String с использованием нового ключевого слова, созданная таким образом строка сохраняется в памяти кучи. Любой строковый литерал, переданный в качестве параметра конструктору класса String, однако, сохраняется в пуле строк. Если мы создадим несколько объектов, используя одно и то же значение с оператором new, новый объект будет создаваться в куче каждый раз, потому что этого нового оператора следует избегать.
«obj1» и «obj2» будут указывать на два разных объекта в куче, а пул строкового литерала будет иметь только один литерал «abc».
Также следует отметить, что в отношении поведения строк следует отметить, что любое новое присваивание или конкатенация, выполняемая со строкой, создает новый объект в памяти.
Теперь в приведенном выше случае:
строка 1: литерал «abc» хранится в пуле строк.
Строка 2: литерал «abcdef» сохраняется в пуле строк.
Строка 3: новый литерал «xyz» сохраняется в пуле строк, и «str1» начинает указывать на этот литерал.
Строка 4: поскольку значение генерируется путем добавления к другой переменной, результат сохраняется в памяти кучи, а добавляемый литерал «ghi» будет проверен на наличие в пуле строк и будет создан, так как он не существует в вышеуказанный случай.
источник
Хотя это выглядит одинаково с точки зрения программистов, оно оказывает большое влияние на производительность. Вы хотели бы использовать первую форму почти всегда.
источник
Он проверит, содержит ли пул констант String строку "hello"? Если он присутствует, он не будет добавлять запись в пул констант String. Если нет, то он добавит запись в пул констант String.
Объект будет создан в области памяти кучи и
str
ссылки будут ссылаться на объект, созданный в области динамической памяти.если вам нужна
str
ссылка на точечный объект, содержащийся в пуле констант String, нужно явно вызватьstr.intern();
Он проверит, содержит ли пул констант String строку "hello"? Если он присутствует, он не будет добавлять запись в пул констант String. Если нет, то он добавит запись в пул констант String.
В обоих вышеупомянутых случаях
str
ссылки на String"world"
присутствуют в пуле констант.источник
Когда вы храните строку как
непосредственно, затем JVM создает объект String с заданной ценой в течение отдельного блока памяти, называемого постоянным пулом String.
И всякий раз, когда мы имеем тенденцию пытаться создать другую строку как
JVM проверяет, существует ли какой-либо объект String с постоянной ценой в пуле констант String, если это так, вместо создания нового объекта JVM назначает ссылку на существующий объект новой переменной.
И когда мы храним String как
используя ключевое слово new, создается совершенно новый объект с заданной ценой независимо от содержимого пула констант String.
источник