Разлика в следните декларации

Не мога да разпозная разликата в следните декларации на низове в Java.

Да предположим, че имам два низа

String str1="one";
String str2="two";

Каква е разликата между

String str3=new String(str1+str2);

и

String str3=str1+str2;

И в двете горни декларации съдържанието на str3 ще бъде onetwo.

Да предположим, че създам нов низ

String str4="onetwo";

Тогава в нито една от горните декларации,

if(str4==str3) {
    System.out.println("This is not executed");
}

Защо str3 и str4 не се отнасят за един и същи обект?


person kevin gomes    schedule 22.03.2015    source източник
comment
Не използвайте == за сравняване на низове   -  person Apurva    schedule 22.03.2015
comment
@Apurva: Искам да сравнявам обекти, а не съдържание на низове. Искам да знам къде се отнасят str4 и str3   -  person kevin gomes    schedule 22.03.2015
comment
това всъщност е сравняване на препратката, т.е. ако str4 и str3 ще сочат към едно и също местоположение, тогава ще се равнява на това, което тук е на различно място.... вместо това използвайте равен метод на низ   -  person Iftikhar Ali Ansari    schedule 22.03.2015
comment
@Iftikhar Защо и къде str3 и str4 се отнасят за различно местоположение   -  person kevin gomes    schedule 22.03.2015
comment
не можете да отпечатате адреса на обект в чиста Java. stackoverflow.com/questions/18396927/   -  person Apurva    schedule 22.03.2015
comment
Why and where str3 and str4 are referring to different location Защо мислите, че трябва да имат една и съща препратка?   -  person Tom    schedule 22.03.2015
comment
@Tom, защото String str3=str1+str2 трябваше да е интерниран низ, а str4 трябва да препраща към същото местоположение като str3   -  person kevin gomes    schedule 22.03.2015
comment
@kevingomes тъй като String str3=str1+str2 трябваше да бъде интерниран не, компилаторът не може да бъде сигурен в стойностите на некрайните променливи, така че не може да ги свърже по време на компилация, както може да направи в случай на "foo"+"bar" и интернирайте го. Той ще го компилира в new StringBuilder(str1).append(str2).toString() и този резултат няма да бъде интерниран.   -  person Pshemo    schedule 22.03.2015


Отговори (4)


str1 + str2 за некомпилирани константни низове ще бъдат компилирани в
new StringBuilder(str1).append(str2).toString(). Този резултат няма да бъде поставен или взет от група низове (където отиват интернираните низове).

Друга е историята в случай на "foo"+"bar", където компилаторът знае с кои стойности работи, така че може да свърже този низ веднъж, за да го избегне по време на изпълнение. Такъв низов литерал също ще бъде интерниран.

Така че String str3 = str1+str2; е същото като

String str3 = new StringBuilder(str1).append(str2).toString();

и String str3 = new String(str1+str2); е същото като

String str3 = new String(new StringBuilder(str1).append(str2).toString());

Отново низовете, произведени в резултат на метод (като substring, replace, toString), не се интернират.
Това означава, че сравнявате два различни екземпляра (които съхраняват едни и същи символи) и затова == връща false.

person Pshemo    schedule 22.03.2015

Java няма памет за това "как тази променлива е получила стойността", следователно наистина няма значение кой метод използвате, ако резултатът е същият.

Относно сравняването, ако сравнявате низове с ==, вие сравнявате адреса на обекти в паметта, тъй като String не е примитивен тип данни, а не стойности. Трябва да използвате if(str4.equals(str3))

person libik    schedule 22.03.2015
comment
Искам да сравня само адреса на обектите. Какво str3 и str4 имат различни препратки - person kevin gomes; 22.03.2015
comment
Има значение какъв метод използваме - person frunkad; 22.03.2015
comment
@kevingomes - google : урок за Java. Всъщност искате да сравнявате стойности, а не адрес в паметта, във вашия пример. Ако жена ви даде живот на близнаци, те може да изглеждат еднакви, но са два различни случая. Ако искате да знаете, ако изглеждат еднакви, използвате равенства, ако искате да знаете, ако са едно и също лице, използвате ==. - person libik; 22.03.2015

Тъй като Strings в Java са неизменни, компилаторът ще оптимизира и използва повторно String литерали. По този начин

String s1 = "one";
String s2 = "one";
s1 == s2; //true because the compiler will reuse the same String (with the same memory address) for the same string literal
s1 == "o" + "ne"; //true because "Strings computed by constant expressions are computed at compile time and then treated as if they were literals"
s3 = "o";
s1 == s3 + "ne"; //false because the second string is created a run time and is therefore newly created

за справка вижте http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

person robertjlooby    schedule 22.03.2015
comment
Използвахте думата immutable - person frunkad; 22.03.2015
comment
may be true as the compiler may ...? Това винаги ще бъде вярно. - person Tom; 22.03.2015
comment
Вярвам, че всеки компилатор ще направи това, така че вероятно ще е вярно на практика. Въпреки това не мисля, че това поведение всъщност е дефинирано в езиковия стандарт, така че не исках да кажа, че винаги ще е вярно, тъй като валиден компилатор може да има различно поведение. - person robertjlooby; 22.03.2015
comment
Interning Strings няма нищо общо с компилатора. - person Tom; 22.03.2015
comment
Прав си, низовите литерали винаги ще бъдат интернирани docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5 коригиране. - person robertjlooby; 22.03.2015

Низовете са доста трудни, защото има известно усилие да се сподели тяхното представяне. Освен това те са неизменни. Краткият отговор е: освен ако наистина не работите на ниско ниво, никога не трябва да сравнявате низове, използвайки "==". Дори и да работи за вас, ще бъде кошмар за съотборниците ви поддържам.

За по-дълъг отговор и малко забавление опитайте следното:

String s1= "a" + "b";
String s2= "a" + "b";
String s3=new String("a"+"b");

System.out.println(s1==s2);
System.out.println(s3==s2);

Ще забележите, че s1==s2 поради усилията на компилатора да споделя. Въпреки това s2 != s3, защото изрично сте поискали нов низ. Едва ли ще направите нещо много умно с него, защото е неизменно.

person Pelit Mamani    schedule 22.03.2015