Skip to content

Rozwiązanie do zadania z Newslettera #10 - 08 maja 2019

Notifications You must be signed in to change notification settings

olekstomek/zadanie-newsletter-10

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 

Repository files navigation

Zadanie Newsletter 10

Rozwiązania do zadania z Newslettera #10 - 08 maja 2019

Do Newslettera można zapisać się na stronie: https://mailtrain.javastart.pl/subscription/tc5pDEzUq

https://youtu.be/4hevGbDXowg?t=154 - omówienie mojego rozwiązania

Omawiany kod:

class StringTask {
    public static void main(String[] args) {
        String string1 = "Hello".concat("World");           // Linia-1
        String string2 = new String("HelloWorld");          // Linia-2
        String string3 = string1.intern();                  // Linia-3
        System.out.println(string1 == string3);             // Linia-4
    }
}

Dlaczego jeżeli w poniższym kodzie usunę Linia-2 to wynik Linia-4 zmieni się z false na true?

Spróbuję to wyjaśnić przedstawiając swoją teorię na ten temat. Wydaje mi się, że pomocne do zrozumienia tego przypadku jest wiedza o tym, że String string2 = new String("HelloWorld") nie tworzy jednego obiektu w pamięci ale dwa obiekty w pamięci. Jeden obiekt jest tworzony w String Pool i jeden poza String Pool. string2 to referencja do obiektu nie będącego w String Pool.

Co robi metoda intern()? Metoda ta pobiera wartość Stringa ze String Pool. W jaki sposób pobiera określa to dokumentacja:

* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>

Czyli jeśli w String Pool jest już dany String (w naszym przypadku "HelloWorld") to zostanie zwrócony, jeśli go nie ma w String Pool to ten String jest dodawany do String Pool i referencja do tego dodanego obiektu jest zwracana. Jeszcze dokładniej co zwraca public native String intern();:

* @return  a string that has the same contents as this string, but is
*          guaranteed to be from a pool of unique strings.

Co ciekawe, referencje do obiektów z wykomentawaną linią 2 czy bez wykomentowanej linii 2 po kompilacji zawsze są takie same:

System.out.println("Hashcode string1 " + System.identityHashCode(string1));
System.out.println("Hashcode string3 " + System.identityHashCode(string3));

true
Hashcode string1 = 356573597
Hashcode string2 = 356573597

System.out.println("Hashcode string1 " + System.identityHashCode(string1));
System.out.println("Hashcode string2 " + System.identityHashCode(string2));
System.out.println("Hashcode string3 " + System.identityHashCode(string3));

false
Hashcode string1 = 356573597
Hashcode string2 = 1735600054
Hashcode string3 = 2168566900

Poleceniem javap -c StringTask.class można wykonać disassemblację kodu i podejrzeć zachowanie w pamięci:

Z Linia-2:

with_Linia-2

Bez Linia-2:

without_Linia-2

Niestety dość ciężko jest mi zrozumieć poszczególne kody, ale przykładowo astore_X (X - cyfra) oznacza przypisanie referencji utworzonej w puli do zmiennej lokalnej, jak widać w przypadku kompilacji bez Linia-2 przypisanie referencji utworzonej w puli do zmiennej lokalnej odbywa się dwa razy: astore_1 i astore_2. W przypadku gdy zwracany jest false występują astore_1, astore_2 i astore_3.

Moja teoria:

  • z Linia-2: Referencja string3 wskazuje na obszar w pamięci na obiekt "HelloWorld" który jest zwracany którego referencja jest zwracana przez metodę intern() ze String Pool (gdzie są przechowywane unikalne elementy w celu oszczędzenia pamięci) zgodnie z tym co powyżej. Jednak w STACK (na stosie) dołożony mamy nowy obiekt "HelloWorld" z inną referencją (new String("HelloWorld")) i to on jest wykorzystany (LIFO). Finalnie więc referencje string1 i string3 są różne, wskazują różne miejsce w pamięci na "HelloWorld". Przez to zwracane są dwie referencje różne - inna referencja dla string1 i inna referencja dla string3 która jest pobrana ze String Pool.

  • bez Linia-2: W przypadku gdy nie mamy linii: String string2 = new String("HelloWorld"); // Linia-2 metoda intern() zwraca Stringa ze String Pool i referencje są identyczne. W String Pool nie mamy "HelloWorld" więc metoda intern() wrzuca obiekt "HelloWorld" do String Pool na który wskazuje string1 i zwraca do niego referncje. Stąd string1 i string3 mają takie same referencje.

About

Rozwiązanie do zadania z Newslettera #10 - 08 maja 2019

Topics

Resources

Stars

Watchers

Forks