Programowania w Javie Działanie kaŝdego programu polega na przetwarzaniu danych. Zaczniemy więc od zapoznania się z typami danych Javy. Aby przetwarzać dane, trzeba umieć na nich operować. Do tego słuŝą operatory, które łączą zmienne, stałe i literały w wyraŝenia. Musimy teŝ umieć zapisywać logikę działania fragmentów programu - w tym celu posługujemy się instrukcjami sterującymi. To są trzy początkowe zagadnienia. Programy w Javie zapisuje się jako definicje klas. Poznamy więc zasady ich konstrukcji oraz działania na obiektach klas za pomocą metod (czyli komunikatów). Ostatnia część rozdziału poświęcona będzie bardzo uŝytecznym obiektom - tablicom. Typy i deklaracje Aby kompilator mógł właściwie interpretować dane i operacje nad nimi, kaŝdej jednostce danych trzeba przypisać typ. Mówi się często, Ŝe typ to zestaw wartości, które moŝe przybierać dana, plus zestaw operacji, które moŝna nad daną wykonywać. O typy Literałów troszczy się sam kompilator (moŝna mu w tym czasem trochę pomóc). Typy zmiennych i stałych, które nie są literałami, programista musi podać sam w deklaracjach. Deklaracje obowiązkowo muszą poprzedzać uŝycie zmiennych i stałych w innych instrukcjach programu. W języku istnieje szereg typów prostych: Wszystkie inne dane w Javie są traktowane jako obiekty, których atrybuty ora; funkcjonalność (moŝliwe operacje na danych) definiują określone klasy. Nazwa klas jest w tym przypadku nazwą typu danego obiektu. Deklaracja zmiennej lub stałej wygląda tak: nazwa_typu nazwa_zmiennej_lub_stałej np.: int a; // deklaracja zmiennej całkowitoliczbowej a char c; // deklaracja zmiennej, która moŝe zawierać znaki Unikodu String s; Button b; Identyfikatory String i Button są nazwami typów obiektowych, nazwami odpowiednich klas (odpowiednio: klasy reprezentującej łańcuchy znakowe oraz klasy przycisków).
Występuje zasadnicza róŝnica pomiędzy deklaracjami zmiennych typów prostych i typów obiektowych. W przypadku typów prostych deklaracja jest zarazem definicją - wydziela w pamięci miejsce na przechowanie zmiennej danego typu. Deklaracja zmiennej typu obiektowego jest faktycznie deklaracją (i definicją) referencji do obiektu, nie wydziela natomiast w pamięci miejsca na przechowanie samego obiektu. Referencja to tylko odniesienie, wskazanie na miejsce w pamięci, gdzie moŝe być przechowywany dany obiekt. Deklarując referencję, nie uzyskujemy obiektu. Obiekt dopiero musimy stworzyć (do czego słuŝy wyraŝenie new, zwracające referencję do nowo utworzonego obiektu). Ewentualnie zadeklarowanej referencji moŝemy przypisać referencję do juŝ istniejącego obiektu. Na przykład po deklaracji: Button b; zmienna b zawiera referencję do obiektu typu Button, ale na razie nie wskazuje na Ŝaden obiekt. Dopiero uŝycie wyraŝenia new: b = new Button(); tworzy obiekt, a zwrócona przez new... referencja jest podstawiana na zmienną b. W deklaracjach moŝemy inicjalizować dane, np.: int a = 1; char c = 'a' ; Button b = new ButtonO; String s = "ala ma kota" //!!! Ostatni przykład nie jest odstępstwem od ogólnej reguły traktowania typów obiektowych. Rzecz w tym, Ŝe w Javie dopuszczalne są literały łańcuchowe (napisy w cudzysłowie), których uŝycie (niewidocznie dla nas) powoduje zbudowanie obiektu typu String i zwrot referencji do niego. Zatem zmienna s zostaje zainicjalizowana referencją do automatycznie utworzonego obiektu typu String, który zawiera napis..ala ma kota". Stałe deklarowane są ze specyfikatorem finał, np. : finał int SIZE = 1024; // nazwy stałych zazwyczaj piszemy duŝymi literami W inicjalizacjach (zarówno zmiennych, jak i stałych) moŝemy uŝywać wyraŝeń iw tym równieŝ wywołania metod). Operatory i wyraŝenia Ze zmiennych, stałych i literałów, posługując się operatorami języka i nawiasami moŝemy konstruować wyraŝenia. WyraŜenia są wyliczane, a ich rezultaty mogą być w róŝny sposób wykorzystane (np. do przypisania wartości wyraŝenia zmiennej, w instrukcjach sterujących wykonaniem programu, jako argumenty metod). Kolejność wyliczeń zaleŝy od priorytetów i wiązań operatorów uŝytych w wyraŝeniach. Priorytety mówią o tym, w jakiej kolejności będą wykonywane róŝne operacje zawarte w tym samym wyraŝeniu (np. czy w wyraŝeniu a + b * c najpierw będzie wykonywane mnoŝenie, czy dodawanie). Wiązania określają kolejność wykonywania operacji o tym samym priorytecie.
Opracowanie wyraŝenia relacyjnego i logicznego daje wynik boolean a > b; // MUSI być typu boolean Nie ma moŝliwości konwersji z boolean do typów całkowitych. W typowych przypadkach, gdzie w C stosowano arytmetykę", na relacjach moŝna uŝyć operatora?: Kolejność opracowania argumentów operacji dwuargumentowych (i listy argumentów wywołania metody) jest ściśle określona: OD LEWEJ DO PRAWEJ.
Operatory +,=,+= mają specjalne znaczenie dla obiektów klasy String: String s; // referencja 3 = "napis"; ' tworzony jest obiekt String zawierający łańcuch "napis" i ODNIESIENIE do tego obiektu przypisywane jest referencji s s = s + "X"; // konkatenacja łańcuchów Z łańcuchami znakowymi moŝna konkatenować dane wszystkich innych typów (w szczególności obiektowych). Przy konkatenacji są automatycznie przekształcane do typu String. W przypadku typów obiektowych oznacza to niejawne wywołanie wobec obiektu metody tostring() z jego klasy lub z którejś z jego nadklas. String sl; String s2 = "Asia"; sl = s2 + " ma psa"; // konkatenacja łańcuchów i przypisanie sl = sl + s2; // sl zawiera napis "Asia ma psa Asia" Z obiektami typu String moŝna konkatenować liczby: nt k = 1; sl = k + k + s2; // od lewej do prawej!!!: da: 2Asia sl = s2 + k + k; // od lewej do prawej!!!: da : Asiall sl = s2 + (k+k); // nawias zmiema kolejność: w wyniku mamy Asia2 sl - k + k; // błąd kompilacji (jeden z argumentów musi być typu String) Jak równieŝ obiekty innych klas: Date date = new Date(); sl = "Data... " + date; // da Data... i bieŝącą datę Do porównywania obiektów nie naleŝy uŝywać operatorów relacyjnych i równości, nierówności. Operatory te zastosowane wobec zmiennych oznaczających obiekty faktycznie porównują referencje (czyli odniesienia do obiektów), bowiem zmienne oznaczają obiekty, ale zawierają referencje. Do porównania obiektów słuŝą metody ich klas: equals(...) i compareto(. ). Porównanie referencji moŝe nam powiedzieć tylko, czy dana referencja wskazuje na ten sam obiekt co inna, ale nie powie nic o tym, czy wskazywane obiekty są treściowo" takie same. String s2 = "Asia"; String s3 = new String("Asia"); boolean b; b = (s2 == s3); // porównanie referencji: wynik false, bo to // nie ten sam obiekt, choć napis jest identyczny b = s2.equals(s3); // porównanie Stringów: wynik true, bo napisy są // takie same. Wyjątek w przypadku literatów łańcuchowych: 32 = "Asia"; s3 = "Asia"; b= (s2 == s3); // true, bo ten sam literalny napis jest jednym obiektem Operator instanceof x instanceof TypObiektowy oznacza: czy x jest referencją do obiektu typu TypObiektowy? Wartość wyraŝenia jest typu boolean (prawda - fałsz, tak - nie). WyraŜenie stwierdza czy x jest obiektem klasy o nazwie TypObiektowy albo dowolnej jej nadklasy, albo klasy implementującej interfejs TypObiektowy. Te groźnie brzmiące sformułowania zostaną dokładnie wyjaśnione w następnych rozdziałach.
Teraz chodzi o ogólne zrozumienie. Oto prosty przykład zastosowania: metoda otrzymuje argument typu Component, naleŝy podjąć róŝne działania w zaleŝności od tego, z jakiej konkretnie podklasy klasy Component pochodzi obiekt, dc którego referencja została przekazana jako argument metody: void metoda(component c) C if (c instanceof Button)... // jeŝeli c oznacza przycisk... robimy cci else if (c instanceof Label)... // a jeŝeli etykietą - to co innego else... // itd. else... Promocje Przy opracowaniu wyraŝeń arytmetycznych zmienne byte, short, char - przekształcane są do typu int, float - do double, long - do float i double. Konwersje arytmetyczne rozszerzające (czyli przekształcające młodsze typy do starszych) są dokonywane niejawnie. ZawęŜające (w odwrotnym kierunku) muszą być dokonane jawnie za pomocą operatora konwersji. Instrukcje Zbiór instrukcji języka Java, wzorowany na zbiorze instrukcji języka C, zawiera: instrukcję przypisania, instrukcje warunkowe if i switch, instrukcje iteracyjne for, while i do, instrukcje sterujące: continue, break blok - ciąg instrukcji w nawiasach W kolejnych podpunktach, omówimy postaci składniowe i semantykę wymienionych instrukcji. W Javie do dyspozycji mamy następujące instrukcje sterujące: if, for, while, switch. Instrukcje warunkowe Instrukcja warunkowa if przyjmuje postać: if (wyraŝenie_logiczne) instrukcja else instrukcja ; lub if (wyraŝenie_logiczne) instrukcja Wykonanie instrukcji polega na obliczeniu wartości wyraŝenia_logicznego i, jeśli jest ona równa true, to wykonaniu podlega pierwsza instrukcja, w przeciwnym przypadku (dla wartości równej false), wykonywana jest instrukcja umieszczona po słowie kluczowym else (jeśli występuje) lub następna instrukcja programu.
W Javie istnieje takŝe moŝliwość łatwego programowania warunków, przyjmujących wartości ze zbioru większego, niŝ dwuelementowy (jak to ma miejsce w instrukcji if). Stosujemy wtedy instrukcję wyboru switch o postaci: switch(wyraŝenie_warunkowe) case stała1: instrukcja case stała2: instrukcja... case stałan: instrukcja [default: instrukcja] W pierwszym kroku wykonania instrukcji obliczana jest wartość wyraŝenia_warunkowego (które przyjmuje wartości całkowite), a następnie porównywana jest ona kolejno z wartościami stałych umieszczonych po słowach case. Sterowanie jest przekazywane do tej instrukcji, w której wartość stałej jest równa wartości wyraŝenia_warunkowego. Jeśli Ŝadna stała nie ma wartości identycznej z wartością wyraŝenia, to wykonywana jest instrukcja umieszczona po słowie default (jeśli jest zdefiniowane) lub następna instrukcja w programie. Instrukcje iteracyjne W Javie mamy do dyspozycji klasyczny zestaw instrukcji iteracyjnych: instrukcję while, pozwalającą programować obliczenia tak długo, jak prawdziwy jest pewien warunek, instrukcje do... while, podobną do poprzedniej, z pewną, opisaną niŝej modyfikacją. instrukcję for, słuŝącą do programowania obliczeń powtarzających się tak długo, jak długo pewna zmienna sterująca przyjmuje wartości z pewnego zbioru, Instrukcja while przyjmuje postać: while (wyraŝenie_logiczne) instrukcja Najpierw obliczana jest wartość wyraŝenia_logicznego. Jeśli jest ona równa true, to wykonywana jest instrukcja, gdy zaś wartość ta równa jest false - sterowanie przekazywane jest do następnej instrukcji programu. Po wykonaniu instrukcji, ponownie sprawdzana jest wartość wyraŝenia_logicznego i procedura powtarza się. Instrukcję do...while moŝna zapisać: do instrukcja while (wyraŝenie_logiczne); Wykonanie tej instrukcji róŝni się od wykonania poprzedniej tym, Ŝe warunek wyraŝenie_logiczne jest sprawdzany po kaŝdym wykonaniu instrukcji, a nie przed, jak to ma miejsce w przypadku instrukcji while. NaleŜy zauwaŝyć, Ŝe jest moŝliwa zmiana opisanego wyŝej trybu wykonania instrukcji iteracyjnych poprzez zastosowanie instrukcji sterujących break i continue, które omówimy później.
Na koniec, zajmiemy się instrukcją for o następującej składni: for (wyraŝenie_1; wyraŝenie_logiczne; wyraŝenie_3) instrukcja Wykonanie instrukcji for przebiega w następujący sposób: Obliczana jest wartość wyraŝenia_1 o Obliczana jest wartość wyraŝenia_logicznego. Jeśli wartość obliczona jest równa true, to wykonywane jest instrukcja, w przeciwnym przypadku, sterowanie przekazywane jest do następnej instrukcji programu o Obliczana jest wartość wyraŝenia_3 Powrót do kroku 2. Zmienne zadeklarowane w wyraŝeniu_1 są widoczne tylko w ciele instrukcji for - po wykonaniu pętli, nie mogą być one ponownie uŝyte. Ta cecha deklaracji zmiennych wykazuje istotną róŝnicę z analogiczną deklaracją w języku C++, gdzie zmienne zadeklarowane w instrukcji for są widoczne są poza nią. Instrukcje sterujące Instrukcje break i continue pozwalają na wcześniejsze opuszczenie pętli. Jeśli break występuje bez etykiety (ang. label) to sterowanie programem przekazywane jest poza instrukcję while lub for. Jeśli instrukcja break posiada etykietę to sterowanie przekazywane jest poza blok instrukcji oznaczonych etykietą. Przykład 2.1 UŜycie instrukcji break z etykietą Przykład ten ilustruje zastosowanie instrukcji break z etykietą do sterowania wykonaniem programu w Javie: int i=0; int k=10; NaszBlok: while(i++<10) if (--k==0) break NaszBlok; System.out.println(i/k); // wyświetlenie na ekranie wyniku dzielenia //Tu zostałoby przekazane sterowanie gdyby instrukcja //break nie miała etykiety NaszBlok. //koniec bloku instrukcji NaszBlok //Tu zostaje przekazane sterowanie programem po wykonaniu //instrukcji break NaszBlok UŜycie instrukcji break z etykietą pozwala na natychmiastowe opuszczenie wielu zagnieŝdŝonych instrukcji while. Instrukcja continue nie powoduje opuszczenia pętli ale natychmiastowe przejście do następnego kroku iteracji. Jeśli uŝyjemy instrukcji continue z etykietą sterowanie przekazywane jest do nawiasu otwierającego blok instrukcji oznaczonych etykietą.
Blok instrukcji Instrukcja złoŝona to ciąg instrukcji pomiędzy nawiasami i, nazywana blokiem instrukcji. Jeśli zadeklarujemy w bloku zmienną to będzie ona widoczna tylko w tym bloku. Przykład 2.2 Widoczność zmiennych w bloku instrukcji Zmienna ta została zadeklarowana tu dwukrotnie, dodatkowo jeszcze jako zmienna róŝnych typów: int i = 10; long i = 5; // moŝemy tu ponowanie zadeklarować zmienną // nazwie 'i', poniewaŝ nie jest tu widoczna zadeklarowana // we wcześniejszym bloku zmienna o tej samej nazwie Źródła "Podstawy programowania w Javie", Krzysztof Barteczko Tutorial "Java - nowy standard programowania w Internecie" Artur Tyloch