1. Porównania
Bardzo często programista musi porównywać ze sobą różne zmienne. I jak już widzieliście, nie wszystko jest takie proste.
Liczby całkowite są bardzo łatwe do porównania - po prostu go użyj ==
i to wszystko. Aby porównać liczby rzeczywiste , musisz już porównać ich różnicę (a raczej moduł różnicy) z jakąś bardzo małą liczbą.
Porównanie ciągów jest jeszcze trudniejsze. A wszystko dlatego, że po pierwsze stringi są obiektami, a po drugie w zależności od sytuacji programista często chce, aby porównanie stringów przebiegało trochę inaczej (uwzględniając lub nie uwzględniając pewnych czynników).
2. Układ ciągów znaków w pamięci
Jak już widziałeś, ciągi znaków są przechowywane w pamięci inaczej niż liczby całkowite i rzeczywiste:
Do przechowywania łańcuchów używane są dwa bloki pamięci : jeden blok przechowuje sam tekst (jego rozmiar zależy od rozmiaru tekstu), a drugi (4 bajty) przechowuje adres pierwszego bloku.
Chociaż doświadczony programista w takiej sytuacji powie coś w stylu „ Zmienna str
typu String
przechowuje odniesienie do obiektu typu String
”.
3. Przypisywanie referencji do ciągów znaków
Korzyść z tego podejścia staje się oczywista, jeśli trzeba przypisać jedną zmienną łańcuchową do innej zmiennej łańcuchowej. Przykład:
String text = "This is a very important message";
String message = text;
A oto, co w rezultacie zostanie w pamięci:
W wyniku tej operacji przypisania obiekt String
pozostanie tam, gdzie był, a message
do zmiennej zostanie skopiowany tylko jego adres (odniesienie do obiektu).
4. Praca z linkami i obiektami
Ale jeśli zdecydujesz się zamienić łańcuch na wielkie litery (wielkie litery), maszyna Java zrobi wszystko dobrze: będziesz mieć dwa obiekty typu String
i zmienne text
i message
będzie przechowywać referencje: każdy do własnego obiektu.
Przykład:
String text = "This is a very important message";
String message = text.toUpperCase();
A oto, co w rezultacie zostanie w pamięci:
Zwracam uwagę na fakt, że metoda toUpperCase()
nie zmienia linii, na której została wywołana. Zamiast tego tworzy nowy ciąg znaków (nowy obiekt) i zwraca do niego odwołanie.
Albo jeszcze ciekawszy przykład. Powiedzmy, że decydujesz się przekazać ciąg znaków do obiektu typu Scanner
(tak, aby odczytywał z niego wartości).
Przykład:
String text = "10 20 40 80";
Scanner console = new Scanner(text);
int a = console.nextInt();
int b = console.nextInt();
Więcej o pracy klasy Scanner
można dowiedzieć się pod linkiem .
Oto jak to wszystko zostanie zapisane w pamięci:
Jednocześnie String
przechowywany jest tam obiekt tego typu, jaki był w pamięci w jednym egzemplarzu - wszędzie przesyłane i przechowywane są tylko odniesienia do niego.
5. Porównywanie odwołań do obiektów typuString
I wreszcie doszliśmy do najciekawszej części - porównań strun.
Do porównania zmiennych łańcuchowych można użyć dwóch operatorów: ==
(równa się) i !=
(nie równa się). Operatory "większy niż", "mniejszy niż", "większy lub równy" nie mogą być użyte - kompilator na to nie pozwoli.
Istnieje jednak interesujący niuans: co przechowujemy w zmiennych łańcuchowych? Zgadza się: adresy (linki) do obiektów. Te właśnie adresy zostaną porównane i będą to:
String text = "Hi";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase();
Oto, co zostanie w pamięci:
Zmienne message
i text
przechowują adres (link) tego samego obiektu. Ale zmienne przechowują s1
również s2
odniesienia do bardzo podobnych obiektów, ale wciąż nie do tego samego obiektu.
A jeśli porównasz te 4 zmienne w kodzie, otrzymasz następujący wynik:
Kod | Wyjście na wyświetlaczu |
---|---|
|
|
GO TO FULL VERSION