2. Wyjątkowa klasa String
Oczywiście, łańcuchy znakowe są obiektami klasy String, zatem wszystko co
dotąd powiedziano o obiektach i referencjach dotyczy także obiektów klasy
String.
Tak jak w przypadku każdej innej klasy obiekty klasy String musimy
bezpośrednio tworzyć.
Mówimy tu o "sztuczkach kompilatora", gdyż omawiane tu wyjątkowe właściwości
klasy String są zapewnianie dzięki niewidocznemu dla programisty przekształceniu
przez kompilator fragmentów kodu w inne (od zastosowanych) konstrukcje składniowe
Javy
Pierwsza "sztuczka" kompilatora polega na tym, że zamiast: String s = new String("Ala ma kota"); możemy napisać: String s = "Ala ma kota"; Zapis ten spowoduje:
Zatem, wyjątkowo, tworząc obiekty klasy String nie musimy używać wyrażenia new. String s1 = "Ala ma kota"; String s2 = " szaroburego"; String s3; s3 = s1 + s2;
spowoduje, że:
Takie zastosowanie operatora + jest wyjątkowe, gdyż (wizualnie) stosujemy
go wobec referencji (np. s1 + s2), co jest niedozwolone. Ale "druga sztuczka"
kompilatora (i tylko kompilatora, bo definicja klasy String w żaden sposób
nie umożliwia takiego zastosowania) powoduje, że możemy to zrobić. String s1 = "Ala ma kota"; String s2 = " szaroburego"; String s3; s3 = s1 + s2 + " w wieku " + 3 + " lat "; Teraz zmienna s3 będzie oznaczać napis "Ala ma kota szaroburego w wieku 3 lat". Operator + jest traktowany jako operator konkatenacji łańcuchów znakowych tylko wtedy, gdy jeden z jego argumentów jest typu String
Zatem np. takie fragmenty będą niepoprawne: Przy konkatenacji należy baczną uwagę zwracać na kolejność opracowywania wyrażeń
Np.
Przy operowaniu na łańcuchach znakowych trzeba szczególnie pamiętać, że dostęp
do nich uzyskujemy za pomocą referencji, co ma swoje konsekwencje przy operacjach
porównania na równość - nierówność. Operatory równości (==) i nierówności (!=) zastosowane wobec zmiennych
oznaczających obiekty , porównują referencje do obiektów, a nie zawartość
obiektów
Zatem poniższy fragment: String s1 = "Al"; String s2 = "a"; String s3 = s1 + s2; String s4 = "Ala"; System.out.println(s3 + " " + s4); if (s3 == s4) System.out.println("To jest Ala"); else System.out.println("To nie Ala" wyprowadzi (wbrew intuicyjnym oczekiwaniom): Do porównywania łąńcuchów znakowych (ich zawartości) nie należy używać operatorów == i !=
Zamiast operatorów == i != używamy metody (polecenia) equals. Aby porównać dwa napisy reprezentowane przez zmienne typu String s1 i s2 piszemy:
s1.equals(s2)
Aby porównać napis reprezentowany przez zmienną s typu String z literałem łańcuchowym piszemy: s.equals(literał_łańcuchowy) Wynikiem jest wartość true jeśli oba napisy są takie same i false w przeciwnym razie.
Poniższy przykładowy program pokazuje różne niuanse operowania na łańcuchach znakowych. public class Strings1 { public static void main(String[] args) { String napis = "Waga "; double w = 10.234; System.out.println(napis + w + " kg"); String txt = napis + w + 10 + " kg"; System.out.println(txt); // dlaczego 10.23410? txt = napis + (w + 10) + " kg"; System.out.println(txt); // a tu 20.234? txt = napis + w * 10 + " kg"; // w*10 bez nawiasów ?.. System.out.println(txt); // ... i dobrze - dlaczego? // (pomoc: priorytety operatorow) String bzdura = "Bzdura"; bzdura = napis; System.out.println(bzdura); // dlaczego wyprowadzi "Waga " a nie "Bzdura" txt = napis; txt = txt + "Ali ?"; System.out.println(txt); // a tu inaczej: System.out.println(napis); // dlaczego napis jest "Waga "? // a nie "Waga Ali ?" System.out.println( napis == bzdura ); // dlaczego true? System.out.println( txt == napis ); // dlaczego false? System.out.println( txt == "Waga Ali ?"); // dlaczego false? System.out.println( txt.equals("Waga Ali ?") ); // dlaczego true? // a teraz coś dziwnego: napis = "Ala"; System.out.println( napis == "Ala"); // true czy false??? } } Waga 10.234 kg
Waga 10.23410 kg Waga 20.234 kg Waga 102.34 kg Waga Waga Ali ? Waga true false false true true Działanie programu przedstawia wydruk (obok). Warto zauważyć, że jako informację do wyprowadzenia przez println (argument w nawiasach okrągłych) możemy podawać również wyrażenia (dodajmy, że dowolnego typu!). Fenomen ten wyjaśnimy sobie w następnych wykładach. Proszę dokładnie przeanalizować tekst programu i przy okazji, odpowiadając na pytania zawarte w komentarzach, sprawdzić swoje rozumienie materialu wykladu.
Ostatni fragment programu pokazuje kolejne "odchylenie" Javy od prostych
reguł. Okazuje się oto, że wszystkie literały łańcuchowe mające ten sam tekst
są jednym i tym samym obiektem. W instrukcji: napis = "Ala"; jest tworzony
nowy obiekt, zawierający napis "Ala". Przy każdym kolejnym użyciu literału
"Ala" w miejsce literału podstawiona będzie referencja do tego obiektu (a
nie do ew. nowotworzonego innego obiektu zawierającego napis "Ala"; taki obiekt nie będzie ponownie tworzony). Jednak nie należy wykorzystywać tej właściwości języka i zawsze, zamiast operatora ==, należy stosować polecenie equals
|