Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moja propozycja rozwiązania #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,81 @@
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](https://user-images.githubusercontent.com/26818304/57659160-9c301900-75e1-11e9-8fc9-33166610b537.PNG)

Bez Linia-2:

![without_Linia-2](https://user-images.githubusercontent.com/26818304/57659159-9c301900-75e1-11e9-93cf-8314a88407f5.PNG)


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.