r07-01, ## Documents ##, XML Vademecum profesjonalisty


Rozdział --> 7[Author:T] .
Język Java

We wcześniejszych rozdziałach opisano sposób obsługi dokumentów XML w Internet Explorerze przy pomocy JavaScriptu. Jednak JavaScript jest językiem o dość przeciętnych możliwościach i poważniejsze projekty programistyczne robione są poza przeglądarkami takimi jak Internet Explorer. Obecnie językiem najpowszechniej stosowanym do obsługi XML jest Java - jest to język, który poznać musi każdy, kto zamierza poważniej zająć się XML.

Nie wolno mylić Javy z JavaScriptem; mimo że podobne są ich nazwy i pewne aspekty składni, to języki te nie są ze sobą spokrewnione. Java to dzieło firmy Sun Microsystems, JavaScript powstał w Netscape. Java jest językiem o możliwościach znacznie większych niż JavaScript.

Z drugiej strony teraz, kiedy już mamy za sobą lekcje JavaScriptu, łatwiej będzie zapoznawać się z Javą, gdyż składnia jest podobna (języki te nie są wprawdzie ze sobą spokrewnione, ale składnia obu z nich wzorowana jest przynajmniej częściowo na C++). W rozdziale tym i następnym nauczymy się używać Javy i najpopularniejszego pakietu obsługi XML w Javie, XML for Java IBM-owskich AlphaWorks.

W tym rozdziale zajmiemy się samą Javą. Znajomość tego języka będzie potrzebna nam w następnych dwóch rozdziałach - musimy poznać klasy Javy i sposób obsługi aplikacji okienkowych.

Poniższy akapit jest niepełny - patrz: komentarz w nim (zaznaczam dodatkowo stylem do Składacza, aby tego braku nie przeoczyć).

W zasadzie tworzenie poważnych aplikacji w Javie jest bardziej złożone niż w JavaScripcie, gdyż Java jest językiem bardziej rozbudowanym. Jak się zapewne domyślasz, język Java jest znacznie obszerniejszy niż to, co opiszemy w tym rozdziale, jeśli chcesz się więcej dowiedzieć, weź odpowiednią książkę. Polecić można --> książki ....[Author:T] Pamiętaj jednak, że w tym rozdziale jest dość informacji, abyś zrozumiał dalsze rozdziały. Jeśli dobrze już znasz Javę, możesz ten rozdział spokojnie pominąć i od razu przejść do następnego, gdzie omówimy DOM XML dostępny dla Javy (w rozdziale 5 zajmowaliśmy się tym samym modelem, ale z punktu widzenia JavaScriptu).

Informacje na temat Javy w Sieci

Java to dzieło firmy Sun Microsystems. Istnieje sporo stron poświęconych temu językowi, dużo z nich jest na serwerach Suna:

Oto kolejna lista adresów, pod które warto zajrzeć. Są to darmowe działające online podręczniki, które pomogą Ci opanować Javę:

Teraz na koniec jeszcze jedna ważna uwaga: Java nie jest językiem dla każdego. Jest to język złożony i na  pełne jego opisanie tysiąca stron byłoby mało. Nie możemy tego języka pominąć, gdyż jest on dla środowiska XML ogromnie ważny, ale jeśli programowanie zdecydowanie Cię nie interesuje, możesz pominąć ten rozdział i dwa następne. Pamiętaj jednak, że praca z XML zapewne prędzej czy później zmusi Cię do poznania języka Java.

Jak się pisze programy w Javie

Język Java zapewne nie jest Ci całkiem obcy - znasz przecież choćby aplety Javy. Aplety, czyli okienkowe aplikacje Javy przeznaczone do pracy w przeglądarkach sieciowych, zdobyły ogromną popularność i wszystkie najważniejsze dzisiaj przeglądarki obsługują tę samą wersję języka. W Internecie znajdziesz miliony gotowych apletów, znajdziesz całe ich darmowe biblioteki. Istnieją nawet aplety przeznaczone do użycia z XML.

Aplet Javy otrzymuje wyznaczony obszar w oknie przeglądarki, może w nim wyświetlać grafikę, kontrolki (takie jak przyciski czy pola tekstowe), tekst i tak dalej. Aplety są interaktywne, gdyż działają w środowisku przeglądarki. Jak już wspomniano, aplety Javy popularność zdobyły bardzo szybko, ale obecnie ich pozycja została znacznie osłabiona, a to z powodu rozwiązań konkurencyjnych, które albo są prostsze w użyciu (na przykład Dynamiczny HTML), albo dają większe możliwości (na przykład Shockwave).

Jednak nie musisz się o Javę zanadto martwić; wprawdzie aplety tracą popularność, ale za to rosną w siłę aplikacje Javy. Głównym powodem jest fakt, że język ten jest niemalże tak silnym narzędziem jak C++, a przy tem jest przenośny między różnymi platformami; możesz na przykład użyć tej samej aplikacji na Windows i na Unixie. Obecnie wiele firm zarzuciło używanie na wewnętrzne potrzeby C++ na rzecz Javy.

Aplikacja Javy nie działa w przeglądarce tak, jak aplet, lecz jest samodzielnym programem. Aplikacje te, podobnie jak aplety, tworzyć mogą własne okna, zresztą później zobaczysz, jak to wygląda. Tak naprawdę aplikacja Javy sama może być przeglądarką, w następnym rozdziale utworzymy aplikację odczytującą z Internetu dokument XML i wyświetlającą na jego podstawie grafikę. Nasz dokument będzie opisywał kółka, jakie mają być narysowane na ekranie.

W naszej pracy z XML skoncentrujemy się na aplikacjach, a nie na apletach Javy (z uwagi na ograniczenia związane z bezpieczeństwem aplety są bardzo ograniczone funkcjonalnie, między innymi niewielkie są ich możliwości w zakresie obsługi plików). Jak zatem tworzy się aplikację Javy? Piszę się aplikację w postaci kodu tego języka, następnie kompiluje się ten kod za pomocą SDK (Java Software Development Kit, w wersjach Javy starszych niż 2 był to Java Development Kit, JDK - z tą ostatnią nazwą nieraz się spotkasz, nawet na stronach Suna). Taka skompilowana aplikacja jest gotowa do użycia.

Aby nie być gołosłownymi, od razu przejdziemy do przykładu. Oto sposób utworzenia aplikacji app, którą zapiszemy w pliku app.java (szczegółami kodu zajmiemy się później):

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

Teraz możemy użyć kompilatora Javy, javac, aby skompilować ten plik do postaci kodu pośredniego app.class - to właśnie app.class będziemy uruchamiali. Właśnie kod pośredni Javy jest przez Javę czytany i uruchamiany. Kod pośredni jest w porównaniu z tekstem bardzo zwarty, dzięki temu aplety są szybko ściągane z Sieci. Ten sam plik z kodem pośrednim można uruchamiać w różnych systemach operacyjnych, czyli kod ten jest przenośny. Poniżej pokazano polecenie kompilujące app.java (używamy tu znaku zachęty % typowo stosowanego w systemie UNIX; w Windows może on przybrać postać C:\XML> lub podobną):

%javac app.java

Utworzony zostanie plik app.class, którego należy używać do uruchamiania aplikacji. Aby aplikację uruchomić, wywołać należy program java rozpowszechniany wraz z Java SDK:

%javac app.java

%java app

Witamy w Javie!

Uruchomiony został nasz kod pośredni z pliku app.class, w wyniku pojawił się tekst Witamy w Javie!. W systemie DOS lub Windows rzecz będzie wyglądała na przykład tak:

--> C:\XML>javac[Author:T] app.java

C:\XML>java app

Witamy w Javie!

Tak właśnie wygląda uruchamianie aplikacji Javy. Istnieje wiele podobieństw między Javą a JavaScriptem, są jednak też między nimi zasadnicze różnice. Na przykład w Javie konieczne jest określanie typów zmiennych, co w JavaScripcie było zbędne. JavaScript jest językiem zorientowanym obiektowo, natomiast Java jest w pełni obiektowa.

Java jest językiem z gruntu obiektowym

Z programowaniem obiektowym pierwszy raz się zetknęliśmy, kiedy używaliśmy JavaScriptu, ale było to bardzo ogólne spojrzenie. W przypadku Javy programowanie obiektowe widać na każdym kroku - przyjrzyj się naszej aplikacji przykładowej:

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

Już w pierwszym wierszu mamy deklarację klasy app. Cały program działa w oparciu o tę klasę, gdyż każda instrukcja zapisana w Javie musi należeć do jakiejś klasy (lub do interfejsu, który jest pojęciem od klasy ogólniejszym). Kiedy Java tę aplikację uruchomi, utworzy obiekt danej klasy i przekaże mu sterowanie. Zatem o ile w JavaScripcie możesz obiektów użyć, to w Javie nie sposób przed nimi uciec.

Teraz przyjrzymy się nieco dokładniej całej idei klas, gdyż musimy temat ten zrozumieć znacznie dokładniej niż wtedy, gdy używaliśmy JavaScriptu. Programowanie obiektowe to po prostu kolejna technika, która umożliwia wcielenie w życie słynnej dewizy dziel i rządź.

Cała sztuka programowania obiektowego polega na zamykaniu danych i funkcji w obiekty, dzięki czemu obiekty te mogą być samodzielnymi jednostkami. Dane obiektu mogą być całkowicie dlań wewnętrzne, czyli prywatne (private), mogą być też udostępniane na zewnątrz, czyli być publiczne (public).

Tak samo jak dane, tak i funkcje mogą być funkcjami prywatnymi bądź publicznymi. W sytuacji idealnej obiekt z resztą programu komunikować powinien się jedynie za pośrednictwem interfejsu złożonego z funkcji publicznych tego obiektu. Jak zapewne pamiętasz z rozdziału 4, funkcje należące do klas (obiektów) nazywamy metodami.

Początkowo programowanie obiektowe stworzono po to, aby ułatwić programistom pracę z dużymi projektami przez podzielenie ich na mniejsze części, które łatwo byłoby objąć. Jak już wiesz, program zawsze można podzielić na funkcje. Programowanie obiektowe idzie jeszcze dalej, gdyż umożliwia tworzenie obiektów zawierających nie jedną, ale wiele funkcji, a oprócz nich także zawierających dane wewnętrzne. Kiedy w obiekcie zamkniesz pewną całość funkcjonalną, możesz przestać zajmować się sposobem zakodowania tego, ale możesz taki obiekt traktować jako czarną skrzynkę realizującą pewne zadanie - i o to właśnie chodzi w programowaniu obiektowym.

Weźmy jako przykład samochód, ale nie traktujmy go jako urządzenia, którym się po prostu jeździ, ale spójrzmy na niego jako na zestaw rurek, drutów, zaworów, przełączników, benzyny i wszystkich tych części, które sprawiają, że całość działa. Teraz wyobraź sobie, że jesteś odpowiedzialny za regulowanie w samochodzie wszystkich funkcji: pompowanie paliwa, jego zapłon, przekazywanie mocy na koła, regulację obwodu elektrycznego i tak dalej. Jeżeli trzeba by było pamiętać o tych wszystkich rzeczach, to lepiej nie kupować takiego pojazdu. A teraz wyobraź sobie, że wszystkie te funkcje są tam, gdzie być powinny - czyli wewnątrz samochodu - i że automatycznie są sterowane, kiedy wciskasz pedał gazu. O całości możesz myśleć jako o samochodzie, pojedynczej rzeczy, która służy do jazdy - wystarczy włączyć stacyjkę i wcisnąć gaz.

Na tym właśnie polega enkapsulacja: cały złożony system, który wymaga ustawiania mnóstwa parametrów, zamienia się na pojedynczy obiekt, który zajmuje się wewnętrznie wszystkimi szczegółami, jeśli tylko mu to nakazać. Jeśli mottem programowania obiektowego było dziel i rządź, to mottem enkapsulacji może być co z oczu, to i z serca.

W przypadku obiektowego programowania w Javie wszystko krąży wokół kilku głównych pojęć: klas, danych klas, metod, obiektów i dziedziczenia --> :[Author:T]

Wszystkie powyższe pojęcia są w programowaniu obiektowym bardzo ważne i zajmiemy się nimi dalej w tym rozdziale, kiedy będziemy tworzyć własne klasy.

Skąd wziąć Java SDK

Jeśli chcesz tworzyć własne aplikacje Javy, musisz zainstalować Java SDK dostępny pod adresem http://java.sun.com/js2e. Po jego ściągnięciu z Sieci - zwykle w postaci jednego pliku wykonywalnego - wystarczy go uruchomić i postępować dalej zgodnie z instrukcjami.

Być może chciałbyś, aby teraz znalazł się tu opis instalacji pakietu Java SDK, ale w tę pułapkę wpadło już zbyt wielu autorów książek. Procedura instalacji zmienia się tak często, że w niejednej książce poświęconej samej Javie opis jest zdezaktualizowany już w chwili wydania książki. Z drugiej strony w przypadku nowszych wersji wystarcza uruchomić ściągnięty program i on zrobi już wszystko, co trzeba.

Zgodnie z zaleceniami Suna musisz upewnić się, że system operacyjny potrafi znaleźć narzędzia Javy, w tym kompilator javac. W tym celu musisz sprawdzić, czy w zmiennej PATH pojawia się podkatalog bin katalogu głównego Javy. Na przykład w Windows, dla Java 2 SDK w wersji 1.2.2 domyślnym katalogiem będzie c:\jdk1.2.2\bin, zatem w pliku autoexec.bat powinno znaleźć się następujące polecenie:

SET PATH=%PATH%;C:\JDK1.2.2\BIN

Aby zmiany te zostały uwzględnione, w niektórych systemach operacyjnych konieczne jest ponowne uruchomienie komputera. Po takiej zmianie ustawień możemy narzędzi Javy używać normalnie w wierszu poleceń. Jeśli tego nie zrobisz, wszystkie nazwy narzędzi Javy będziesz musiał poprzedzać pełną ścieżką dostępu.

Tworzenie plików Javy

Kod Javy zawierający instrukcje i deklaracje tego języka będziemy przechowywali w zwykłych plikach tekstowych. Do edycji wystarczy użyć dowolnego edytora tekstowego, jeśli jednak używasz procesora tekstu, musisz pamiętać o zapisywaniu wyników pracy w zwykłych plikach tekstowych.

Rozszerzeniem plików z kodem powinno być .java, gdyż takiego rozszerzenia oczekuje kompilator. Naszą pierwszą aplikację zapisaliśmy w pliku app.java, nazwę tego pliku przekazaliśmy kompilatorowi jako parametr. O jednej ważnej rzeczy musisz pamiętać: nazwa pliku musi być taka sama, jak nazwa klasy, która jest w tym pliku.

Zatem przygotowaliśmy już potrzebne nam narzędzia, teraz czas wziąć się za pisanie kodu.

Pisanie kodu: tworzenie aplikacji

Oto przykładowa aplikacja, której tworzeniem zajmiemy się w następnych kilku punktach. Kod zapisz w pliku app.java:

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

Wiesz już, że aplikacja ta po prostu wypisze pewien tekst - w oknie DOS w Windows wyglądać to będzie tak:

C:\XML>java app

Witamy w Javie!

Może nie jest to program na miarę Twoich ambicji, ale wystarczy na początek. Teraz przyjrzymy się dokładnie, co się dzieje w pliku app.java.

public class app

Zwróć uwagę na pierwszy wiersz pliku app.java:

public class app

{

.

.

.

}

Pierwszy wiersz mówi, że tworzymy nową klasę Javy o nazwie app. Kiedy plik ten skompilujemy do postaci kodu pośredniego, sama Java utworzy obiekt tej klasy i przekaże mu sterowanie.

Zwróć uwagę na słowo kluczowe public. Jest to określenie dostępności. Kiedy użyjesz słowa public, klasa jest dostępna w dowolnym miejscu programu. Klasa główna aplikacji Javy zawsze musi być klasą publicznie dostępną. Zresztą Java wymaga nazwania pliku tak samo, jak się nazywa klasa główna i dodania rozszerzenia .java. Wielkość liter ma znaczenie - klasa nazywać się będzie właśnie app, nie APP czy App. Jako że nazwa klasy publicznej pliku, w którym klasa ta jest zdefiniowana narzuca nazwę tego pliku, w jednym pliku nie umieszcza się więcej niż jednej klasy publicznej.

Za wierszem public class app znajduje się --> para nawiasów klamrowych.[Author:T] Tak jak kod metod zapisywałeś w nawiasach klamrowych, tak samo zapisywać musisz kod obiektów.

public static void main(String[ ] args)

W następnym wierszu aplikacji znajdziesz coś takiego:

public class app

{

public static void main(String[] args)

{

.

.

.

}

}

Zaczynamy definiowanie funkcji należącej do obiektu, czyli metody. Jest to metoda publiczna, zatem będzie dostępna (będzie ją można wywołać) także poza obiektem. Metody zadeklarowane jako prywatne nie mogą być wywoływane spoza obiektu (i są zwykle metodami pomocniczymi używanymi przez inne metody danego obiektu). Tak jak w przypadku funkcji JavaScriptu, metodom można przekazywać parametry, metody mogą też zwracać wartości. Więcej o tym powiemy później, na razie przyjmijmy, że mamy do czynienia z metodą main, która żadnej wartości nie zwraca - wskazuje na to słowo kluczowe void. Metoda main jest w Javie metodą szczególną, gdyż to ona właśnie będzie automatycznie wywołana przy uruchomieniu aplikacji. Kiedy Java znajdzie metodę main, przekaże jej sterowanie (aplety nie mają takiej metody, na tym polega główna różnica w programowania apletów i aplikacji Javy). Do opisywanej metody wstawia się kod, który ma być uruchomiony przy uruchomieniu aplikacji.

Poinformowaliśmy także Javę, że metoda otrzymuje jako parametr tablicę obiektów String - w nawiasach po nazwie metody zapisaliśmy String[] args. Trzeba deklarować typy wszystkich parametrów przekazywanej metodzie, tutaj użyliśmy zapisu String[], co oznacza tablicę napisów. Tablicę tę nazwano args, pod tą nazwą tablica dostępna będzie w kodzie. Taka tablica jest przekazywana metodzie main każdej aplikacji - używamy jej do wskazania parametrów wywołania z wiersza poleceń. Tematem tym dokładniej zajmiemy się nieco dalej.

Zwróć uwagę jeszcze na słowo kluczowe static. Formalnie rzecz biorąc main jest metodą klasy głównej aplikacji, app. Obiektu klasy app nie tworzy się w kodzie jawnie, pozostaje on tylko klasą. Z tego powodu metody i dane klasy app są metodami i danymi klasy, a nie obiektu. Istnieje ogólna reguła dotycząca metod i danych klas: zawsze muszą być deklarowane ze słowem kluczowym static, co powoduje, że Java przechowuje je w szczególny sposób. Kiedy zostaną zadeklarowane jako static, można do nich sięgać przez klasę bez konieczności tworzenia obiektów takiej --> klasy.[Author:T]

Reszta metody main jak zwykle znajduje się w nawiasach klamrowych. Zadaniem tej metody jest wypisanie tekstu Witamy w Javie!, do tego służy następny wiersz.

System.out.println("Witamy w Javie!");

Metoda main zawiera jeden tylko wiersz:

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

Jest to jedyny wiersz naszego programu, który robi cokolwiek, co zobaczy użytkownik - wypisuje podany kod.

Używamy tu funkcjonalności wbudowanej w Javę. Tak jak JavaScript, tak i Java zawiera mnóstwo klas i obiektów gotowych do użycia. W Javie te funkcje pogrupowane są w pakiety (czyli biblioteki klas). Jednym z takich pakietów jest java.lang, pakiet samego języka Java, który zawiera klasę System, która z kolei zawiera obiekt statyczny out, który umożliwia komunikację z użytkownikiem. W tym wypadku użyto metody println tego obiektu - powoduje ona wyświetlenie tekstu na konsoli.

Warto zauważyć jeszcze jedno: wiersz kończy się średnikiem. Kończenie każdej instrukcji średnikiem jest standardem w językach takich jak C, C++, Java, a nawet JavaScript. W przypadku JavaScriptu średniki te mogliśmy pomijać, gdyż nie wymagała ich przeglądarka, ale w Javie to już co innego. Średniki są obowiązkowe; jeśli zaczynasz uczyć się Javy po JavaScripcie, możesz dojść do wniosku, że Java jest językiem bardzo nieprzyjemnym; nie dość, że te średniki, to jeszcze trzeba określać typy wszystkich zmiennych i parametrów. Jeśli spróbujesz przypisać zmiennej jednego typu daną innego typu (co w JavaScripcie świetnie zadziała), Java wygeneruje komunikat o błędzie.

Tak więc utworzyliśmy nową aplikację i zapisaliśmy ją w pliku app.java. Co dalej? Jak teraz ten program uruchomić?

Kompilacja kodu

Mamy już plik app.java, teraz chcemy go uruchomić. Pierwszy krok to skompilowanie go do postaci kodu pośredniego w pliku app.class. Użyjemy kompilatora javac (w systemie Windows plik ten nazywa się javac.exe i znajduje się w podkatalogu bin katalogu instalacyjnego JDK). Oto ogólne zasady używania tego programu (wszystkie parametry są opcjonalne, dlatego umieszczamy je w nawiasach kwadratowych - jest to konwencja używana przez Suna w dokumentacji Javy).

javac [opcje] [plikiźródłowe] [pliki]

Oto znaczenie poszczególnych parametrów:

Parametr

Opis

opcje

Opcje wiersza poleceń - szczegółów na ten temat szukaj w dokumentacji Javy. Opcji tych nie będziemy używać.

plikiźródłowe

Jeden lub więcej plików źródłowych, które mają być skompilowane (w naszym wypadku jest to app.java).

pliki

Jeden lub więcej plików, do których mają być skompilowane pliki źródłowe.

W naszym wypadku plik app.java skompilujemy stosując polecenie:

%javac app.java

Kompilator javac skompiluje plik app.java i jeśli nie wystąpią żadne błędy, zapisze uzyskany kod pośredni w pliku app.class. Jeśli jakieś błędy się pojawią, kompilator je pokaże wraz z numerem wiersza, w którym wystąpiły. Jeśli na przykład zamiast println napiszemy printText, uzyskamy taki oto wynik:

%javac app.java

app.java:5: Method printText(java.lang.String) not found in class

java.io.Print

Stream.

System.out.printText("Witamy w Javie!");

^

1 error

U nas jednak żadne błędy nie wystąpiły, zatem uzyskamy kod pośredni app.class, który może być przez Javę uruchamiany. Dokładnie taki sam plik będzie używany na wszystkich komputerach obsługujących Javę.

Uruchamianie aplikacji Javy

Aplikacje Javy uruchamia się za pośrednictwem odpowiedniego narzędzia, które nazwano - żeby łatwo było zapamiętać - java. Jest to program dostarczany wraz z Java SDK (plik java.exe w podkatalogu bin w przypadku Windows).

Uruchamianie aplikacji Javy bez SDK

Jeśli zamierzasz tylko uruchamiać aplikacje Javy, nie musisz od razu instalować całego Java SDK. Wystarczy JRE (Java Runtime Environment, Środowisko uruchamiania Javy), które dostępne jest na stronie Suna http://java.sun.com/js2e.

Aplikację Javy uruchamia się poleceniem java, na przykład tak:

%java app

Wynik pojawia się natychmiast:

%java app

Witamy w Javie!

To samo pokazano na rysunku 7.1, gdzie aplikację uruchomiono w okienku DOS w Windows.

Rysunek 7.1.

Uruchamianie aplikacji Javy

0x01 graphic

I to już wszystko: utworzyliśmy, skompilowaliśmy i uruchomiliśmy naszą pierwszą aplikację Javy. Jeśli Twoja aplikacja nie odpowiada lub chcesz przerwać jej działanie, wciśnij Ctrl-C. Jeśli to nie działa, spróbuje jeszcze klawisza Escape.

Skoro jesteśmy przy temacie kompilowania i uruchamiania kodu, powinniśmy omówić jeszcze jedną kwestię: komentowanie kodu Javy.

Komentowanie kodu

Tak jak w JavaScripcie, tak i w Javie można do kodu wstawiać komentarze, służą one też do tego samego, co w JavaScripcie i XML - mają objaśniać kod. W Javie komentarze można wstawiać dwojako: można tekst komentarza otoczyć znakami /* i */, na przykład tak:

/* Aplikacja ma wyświetlić na konsoli napis

"Witamy w Javie!".

*/

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

Oczywiście cała treść komentarza zostanie przez kompilator pominięta. Komentarze takie są szczególnie przydatne do wstawiania długich, wielowierszowych komentarzy.

Tak samo jak w JavaScripcie, tak i w Javie można definiować krótkie komentarze, zaczynające się dwoma ukośnikami // i kończące się wraz z końcem wiersza. W ten sposób zwykle wstawia się pojedyncze wiersze komentarza lub komentuje się poszczególne instrukcje:

/* Aplikacja ma wyświetlić na konsoli napis

"Witamy w Javie!".

*/

public class app //Definiujemy klasę app.

{

//Definiujemy automatycznie wywoływaną metodę main().

public static void main(String[] args)

{

//Wyświetlamy komunikat "Witamy w Javie!".

System.out.println("Witamy w Javie!");

}

}

Istnieje jeszcze jeden typ komentarzy, są to komentarze JavaDoc, które wykorzystywane są przez narzędzie javadoc do dokumentowania programu. Zaczynają się od /** i kończą tradycyjnie */.

Importowanie klas i pakietów Javy

Jak już wspomniano wcześniej, Sun zestawił wiele gotowych do użycia klas w biblioteki klas zwane pakietami. Klasy, których będziemy używać do pracy z XML w następnych dwóch rozdziałach, także znajdują się w pakietach. Wprawdzie pakiet java.lang jest domyślnie dostępny w kodzie, ale inne pakiety już nie i przed ich użyciem konieczne jest ich zaimportowanie. Można importować poszczególne klasy lub od razu cały pakiet. Znajomość tego zagadnienia jest bardzo istotna dla programisty Javy, gdyż mnóstwo klas używanych zwykle w programach znajduje się w pakietach i trzeba je importować.

Aby zaimportować pakiet, używa się instrukcji import o następującej składni:

import [pakiet1[.pakiet2...].](nazwaklasy|*);

Zgodnie z konwencją Suna fragmenty ujęte w nawiasy kwadratowe jest opcjonalne, natomiast kreska pionowa oznacza alternatywę, tak jak w DTD.

Zwróć uwagę na kropkę między nazwami pakietów i klasy, która je od siebie oddziela. Standardowe pakiety Javy są grupowane w duży pakiet java, zatem pakiet util będzie wywoływany jako java.util. Dostępne są też inne tak skonstruowane duże pakiety, na przykład pakiet Swing znajdujący się w pakiecie javax.

Oto przykład: chcemy użyć klasy Date zdefiniowanej w pakiecie java.util. Instrukcja importująca wyglądać będzie następująco:

import java.util.Date;

public class app

{

public static void main(String[] args)

{

.

.

.

}

}

Teraz możemy już w kodzie używać klasy Date. Wystarczy utworzyć nowy obiekt Date za pomocą operatora new, tak samo, jak to robiliśmy w JavaScripcie. Nowy obiekt Date reprezentuje datę dzisiejszą. Zwróć uwagę na pustą parę nawiasów dołączaną do konstruktora klasy - w ten sposób zaznaczamy, że konstruktor nie otrzymuje żadnych parametrów. Jak zapewne pamiętasz z wykładu JavaScriptu, konstruktor jest specyficzną metodą uruchamianą przy tworzeniu nowego obiektu danej klasy, w której można przeprowadzić potrzebne inicjalizacje.

import java.util.Date;

public class app

{

public static void main(String[] args)

{

System.out.println("Dzisiaj jest " + new Date());

}

}

Kiedy ten program skompilujesz i uruchomisz, uzyskasz wynik mniej więcej taki:

%java app

Dzisiaj jest Tue Dec 26 12:49:53 GMT+1:00 2000

W tym wypadku importowaliśmy konkretną klasę, Date, z pakietu java.util. Nic jednak nie stoi na przeszkodzie, aby zaimportować od razu wszystkie klasy pakietu - stosuje się do tego gwiazdkę *. Plik app.class nie stanie się przez to ani trochę większy. W kodzie wynikowym umieszczone zostaną jedynie te klasy, które są faktycznie wywoływane, zatem plik app.class będzie taki sam niezależnie od tego, czy użyjemy instrukcji import java.util.Date;, czy import java.util.*:

import java.util.*;

public class app

{

public static void main(String[] args)

{

System.out.println("Dzisiaj jest " + new Date());

}

}

Można także importować klasy własnoręcznie zdefiniowane. Załóżmy na przykład, że zdefiniowaliśmy klasę Display zawierającą metodę showImage wyświetlającą na ekranie obrazek. Jeśli chcemy skorzystać z tej metody, nowy obiekt tworzymy następująco:

public class app

{

public static void main(String[] args)

{

(new Display()).showImage("kwiatki.gif");

}

}

Po utworzeniu pliku Display.class klasę Display importuje się następująco:

import Display;

public class app

{

public static void main(String[] args)

{

(new Display()).showImage("kwiatki.gif");

}

}

W pokazanym przykładzie zakładamy, że plik Display.class jest w tym samym katalogu, co kompilowana aplikacja - wtedy instrukcja import będzie potrafiła znaleźć plik. Jeśli klasa Display ma być jednak w innym katalogu, na przykład C:\display, należy taki katalog dodać do zmiennej środowiskowej CLASSPATH. Więcej na ten temat powiemy jeszcze później, możesz też zajrzeć do dokumentacji Javy.

Tworzenie w Javie zmiennych

Wiemy już, że konstrukcja aplikacji Javy oparta jest na klasach, mamy też dość podstawowych wiadomości, aby zacząć pisać proste programy. Zaczniemy od tego, jak można w Javie przechowywać dane. Tak jak w JavaScripcie, zmienne są miejscami w pamięci, w których można umieszczać dane. Jednak w przeciwieństwie do JavaScriptu, zmienne Javy mają ściśle określone typy, co oznacza, że podczas definiowania zmiennych musisz typy starannie dobierać. Jest to jedna z zalet Javy, gdyż typy podstawowe zawsze są dokładnie takie same i programista nie musi martwić się o szczegóły działania operacji zmiennoprzecinkowych czy kolejność bajtów w słowie.

I tak jednym z najpowszechniej stosowanych typów zmiennych jest int, który oznacza liczby całkowite (ang. integer). Typ ten zajmuje cztery bajty, można zatem przechowywać w zmiennych tego typu liczby od -2 147 483 648 do 2 147 483 647. W Javie zdefiniowany jeszcze inne typy proste pozwalające zapisywać liczby całkowite, liczby zmiennoprzecinkowe czy pojedyncze znaki.

Jeśli chcesz w Javie jakiejś zmiennej użyć, musisz ją najpierw zadeklarować podając jej typ:

typ nazwa [= wartość][, nazwa [= wartość]...];

Oto przykład, w którym deklarujemy zmienną typu int o nazwie licznik:

public class app

{

public static void main(String[] args)

{

int licznik;

.

.

.

}

}

Zarezerwowaliśmy dla zmiennej o nazwie licznik cztery bajty pamięci. Za pomocą operatora przypisania możemy w zmiennej tej umieścić wartość 2001:

public class app

{

public static void main(String[] args)

{

int licznik;

licznik = 2001;

.

.

.

}

}

Wartość tej zmiennej wyświetlić możemy stosując instrukcję println:

public class app

{

public static void main(String[] args)

{

int licznik;

licznik = 2001;

System.out.println("Licznik ma obecnie wartość " + licznik);

}

}

W wyniku działania takiej aplikacji uzyskamy:

%java app

Licznik ma obecnie wartość 2001

Tak jak w JavaScripcie możemy w jednej instrukcji zmienną zadeklarować i od razu nadać jej wartość:

public class app

{

public static void main(String[] args)

{

int licznik = 2001;

System.out.println("Licznik ma obecnie wartość " + licznik);

}

}

W Javie istnieje wiele typów wbudowanych poza int:

Jako że Java jest językiem, w którym typy odgrywają dużą rolę, bardzo istotny jest sposób łączenia typów. Przyjrzyj się poniższemu fragmentowi kodu: deklarujemy zmienne całkowitoliczbową i zmiennoprzecinkową, następnie liczbę zmiennoprzecinkową przypisujemy zmiennej całkowitej:

public class app

{

public static void main(String[] args)

{

float licznik = 2001;

int licznik2;

licznik2 = licznik;

System.out.println("Licznik2 ma obecnie wartość " + licznik2);

}

}

Dla Javy jest to już problem, gdyż liczba zmiennoprzecinkowa może mieć więcej miejsc znaczących niż liczba typu int. Próba kompilacji tego kodu zakończy się błędem, kompilator zażąda „jawnego rzutowania” (explicit cast) liczby zmiennoprzecinkowej na całkowitą:

% javac app.java

app.java:8: Incompatible type for =. Explicit cast needed to convert float to int.

licznik2 = licznik;

^

1 error

Problemu tego można uniknąć, jeśli zażądamy od Javy jawnej konwersji typu za pomocą operatora rzutowania na typ całkowitoliczbowy, (int):

public class app

{

public static void main(String[] args)

{

float licznik = 2001;

int licznik2;

licznik2 = (int) licznik;

System.out.println("Licznik2 ma obecnie wartość " + licznik2);

}

}

Poszczególne typy można w miarę potrzeb konwertować, ale musisz pamiętać, że może to spowodować utratę dokładności.

Tworzenie w Javie tablic

Typy proste, którymi zajmowaliśmy się w poprzednim rozdziale, są wygodne do przechowywania pojedynczych danych, jednak często dane są znacznie bardziej złożone. Tak jak w JavaScripcie, tak i w Javie można używać tablic. Oto przykład - w tablicy chargesDue będziemy zapisywać długi klientów. Zaczynamy od zadeklarowania tablicy typu double:

public class app

{

public static void main(String[] args)

{

double chargesDue[];

.

.

.

Zanim będzie można tej tablicy użyć, musimy określić liczbę jej elementów. Robi się to za pomocą operatora new:

public class app

{

public static void main(String[] args)

{

double chargesDue[];

chargesDue = new double[100];

.

.

.

Deklarację tablicy można połączyć w jedną instrukcję z jej definicją:

public class app

{

public static void main(String[] args)

{

double chargesDue[] = new double[100];

.

.

.

Kiedy tablicę już zdefiniowaliśmy, można do pojedynczych elementów odwoływać się stosując indeks tablicy w nawiasach kwadratowych:

public class app

{

public static void main(String[] args)

{

double chargesDue[] = new double[100];

chargesDue[4] = 99.06;

System.out.println("Klient 4 winien jest " + chargesDue[4]);

}

}

W wyniku działania tego kodu otrzymamy:

%java app

Klient 4 winien jest 99.06

W Javie najmniejszym indeksem tablicy jest 0, zatem instrukcja chargesDue = new double[100] tworzy tablicę, której pierwszym elementem jest chargesDue[0], zaś ostatnim chargesDue[99].

Można też inicjalizować tablice w chwili ich tworzenia. Robi się to podając listę wartości oddzielonych przecinkami, ujętych w nawiasy klamrowe. Tablica będzie miała tyle elementów, ile wartości podano:

public class app

{

public static void main(String[] args)

{

double chargesDue[] = {1093.66, 667.19, 45.99, 890.30, 99.06};

.

.

.

Załóżmy teraz, że dług klienta zapisujemy osobno dla każdego oddziału firmy i w tej chwili mamy oddział wschodni i zachodni. Jeśli klient otworzy w obu z nich rachunek, musimy mieć dla niego dwa bilanse. Używa się do tego tablicy dwuwymiarowej:

public class app

{

public static void main(String[] args)

{

double chargesDue[][] = new double[2][100];

.

.

.

Teraz do każdego elementu odwołujemy się używając dwóch indeksów:

public class app

{

public static void main(String[] args)

{

double chargesDue[][] = new double[2][100];

chargesDue[0][4] = 99.06;

chargesDue[1][4] = 23.17;

.

.

.

Możemy już wyświetlać dług klienta osobno w obu działach, na przykład tak:

public class app

{

public static void main(String[] args)

{

double chargesDue[][] = new double[2][100];

chargesDue[0][4] = 99.06;

chargesDue[1][4] = 23.17;

System.out.println("Klient 4 winien jest " +

chargesDue[0][4] + " w oddziale wschodnim.");

System.out.println("Klient 4 winien jest " +

chargesDue[1][4] + " w oddziale zachodnim.");

}

}

Oto wyniki:

%java app

Klient 4 winien jest 99.06 w oddziale wschodnim.

Klient 4 winien jest 23.17 w oddziale zachodnim.

Tabelę dwuwymiarową można także zainicjalizować podając wartości jej elementów:

public class app

{

public static void main(String[] args)

{

double chargesDue[][] ={{1093.66, 667.19, 45.99, 890.30, 99.06},

{2019.00, 129.99, 19.01, 630.90, 23.17}};

System.out.println("Klient 4 winien jest " +

chargesDue[0][4] + " na wschodzie.");

System.out.println("Klient 4 winien jest " +

chargesDue[1][4] + " na zachodzie.");

}

}

Określanie długości tablicy

Jeśli musisz znać długość tablicy, wystarczy użyć właściwości length, na przykład wyniki.length.

Napisy w Javie

Zapewne zauważyłeś już, że w Javie można stosować operator + do łączenia napisów - zupełnie jak w JavaScripcie:

public class app

{

public static void main(String[] args)

{

double chargesDue[][] ={{1093.66, 667.19, 45.99, 890.30, 99.06},

{2019.00, 129.99, 19.01, 630.90, 23.17}};

System.out.println("Klient 4 winien jest " +

chargesDue[0][4] + " na wschodzie.");

System.out.println("Klient 4 winien jest " +

chargesDue[1][4] + " na zachodzie.");

}

}

Działa to dlatego, że napisy są wbudowaną klasą String. Klasa ta jest w Javie traktowana szczególnie, można używać jej tak, jak innych typów wbudowanych, jak to pokazano w poniższym przykładzie (zwróć uwagę na to, że nie musimy używać do wywołania konstruktora klasy String operatora new):

public class app

{

public static void main(String[] args)

{

String powitanie = "Witamy w Javie!";

.

.

.

Nową zmienną String można traktować tak, jak zmienne typów prostych - można na przykład wypisać jej wartość:

public class app

{

public static void main(String[] args)

{

String powitanie = "Witamy w Javie!";

System.out.println(powitanie);

}

}

Tak naprawdę Java dysponuje dwiema klasami do obsługi napisów: String oraz StringBuffer. Obiekt String przeznaczony jest tylko do odczytu, niemożliwa jest zmiana jego danych wewnętrznych, można natomiast zmieniać dane obiektów klasy StringBuffer. Obie klasy zawierają wiele metod, których opis znajdziesz w dokumentacji Javy.

Operatory w Javie

Operatory są ważną częścią wszystkich języków programowania, zatem także Javy. Oto przykład użycia operatora + dodającego dwie liczby:

public class app

{

public static void main(String[] args)

{

int int1 = 130, int2 = 250, suma;

suma = int1 + int2;

System.out.println(int1 + " + " + int2 + " = " + suma);

}

}

Oto wynik:

%java app

130 + 250 = 380

W tablicy 7.1 zestawiono operatory dostępne w Javie - zwróć uwagę, że prawie wszystkich z nich wystąpiły też w JavaScripcie.

Tabela 7.1.
Operatory Javy

Operator

Wykonywana operacja

++

inkrementacja

--

dekrementacja

=

przypisanie

==

równość

+

dodawanie

+=

dodawanie i przypisanie

-

odejmowanie

-=

odejmowanie i przypisanie

*

mnożenie

*=

mnożenie i przypisanie

/

dzielenie

/=

dzielenie i przypisanie

<

mniejszość

<=

mniejszość bądź równość

<<

przesunięcie w lewo

<<=

przesunięcie w lewo i przypisanie

>

większość

>=

większość bądź równość

>>

przesunięcie w prawo

>>=

przesunięcie w prawo i przypisanie

>>>

przesunięcie w prawo połączone z wypełnianiem zerami

>>>=

przesunięcie w prawo połączone z wypełnianiem zerami i przypisanie

^

logiczne alternatywa wykluczająca (XOR)

^=

logiczna alternatywa wykluczająca (XOR) z przypisaniem

|

logiczna alternatywa (OR)

||

bitowa alternatywa

||=

bitowa alternatywa z przypisaniem

|=

bitowa alternatywa (OR) z przypisaniem

~

bitowa negacja

!

logiczna negacja (NOT)

!=

nierówność

&

--> bitowa koniunkcja[Author:T]

&&

logiczna koniunkcja (AND)

&=

bitowa koniunkcja z przypisaniem

?:

trójargumentowy operator, odpowiednik instrukcji if...else

%

modulo

%=

modulo z przypisaniem

Instrukcje warunkowe Javy: if, if...else, switch

Następną konstrukcją języka po operatorach są instrukcje warunkowe. Java dysponuje takimi instrukcjami tego rodzaju, jak JavaScript: if, if...else i switch.

Instrukcja if umożliwia sprawdzenie jakiegoś warunku, który buduje się za pomocą operatorów porównania, takich jak <, > czy ==,

if (warunek) {

kod uruchamiany, kiedy warunek jest prawdziwy

}

else {

kod uruchamiany, kiedy warunek nie jest prawdziwy

}

Załóżmy na przykład, że mamy dwie zmienne typu double, srodki oraz zadluzenie i chcemy je porównać, aby sprawdzić wypłacalność i wyświetlić odpowiedni komunikat (w Javie, jeśli napis zawierać ma cudzysłów lub apostrof, konieczne jest cytowanie go odwróconym ukośnikiem, na przykład ' nie można zapisać jako "'", lecz jako "\'":

public class app

{

public static void main(String[] args)

{

double srodki = 157.99;

double zadluzenie = 115.99;

if (srodki > zadluzenie) {

System.out.println("Jesteś wypłacalny.");

}

}

}

Instrukcja if sprawdza prawdziwość warunku i jeśli okaże się on prawdziwy, uruchamiany jest kod klauzuli if. W takim wypadku nasz program wyświetli komunikat:

%java app

Jesteś wypłacalny.

Można też obsługiwać przypadek, kiedy warunek okaże się fałszywy - stosuje się frazę else. Jeśli warunek jest fałszywy, uruchamiany jest właśnie kod frazy else, jeśli fraza taka istnieje. Oto przykład - jeśli środki posiadane nie są większe od zadłużenia, wyświetlany jest inny komunikat:

public class app

{

public static void main(String[] args)

{

double srodki = 157.99;

double zadluzenie = 115.99;

if (srodki > zadluzenie) {

System.out.println("Jesteś wypłacalny.");

}

else {

System.out.println("O, kurczę!");

}

}

}

Można też tworzyć całe „drabinki” instrukcji if...else, jak poniżej, gdzie rozważamy już trzy przypadki:

public class app

{

public static void main(String[] args)

{

double srodki = 157.99;

double zadluzenie = 115.99;

if (srodki > zadluzenie) {

System.out.println("Jesteś wypłacalny.");

}

else {

if(srodki == zadluzenie) {

System.out.println("Jestes splukany.");

}

else {

System.out.println("O, kurczę!");

}

}

}

}

Tak jak w przypadku JavaScriptu, tak i Java obsługuje instrukcję switch:

switch(warunek){

case wartość1:

kod uruchamiany, jeśli warunek pasuje do wartości1

break;

case wartość2:

kod uruchamiany, jeśli warunek pasuje do wartości2

break;

.

.

.

default:

kod uruchamiany, jeśli warunek nie pasuje do żadnej wartości

break;

}

Jest tu jednak pewna pułapka: nie można użyć wielu typów zmiennych oferowanych przez Javę. Jedyne typy zmiennych, których można użyć w instrukcji switch, to byte, char, short i int. Oto przykład wykorzystani liczb całkowitych int:

public class app

{

public static void main(String[] args)

{

int dzien = 5;

switch(day) {

case 0:

System.out.println("Dzisiaj jest niedziela.");

break;

case 1:

System.out.println("Dzisiaj jest poniedziałek.");

break;

case 2:

System.out.println("Dzisiaj jest wtorek.");

break;

case 3:

System.out.println("Dzisiaj jest środa.");

break;

case 4:

System.out.println("Dzisiaj jest czwartek.");

break;

case 5:

System.out.println("Dzisiaj jest piątek.");

break;

default:

System.out.println("W takim razie musi być sobota.");

}

}

}

Jest jeszcze jedna wygodna metoda obsługi konieczności wyboru: można użyć operatora trójargumentowego ?:. Operator ten zwraca jedną z dwóch wartości w zależności od tego, czy podane jako pierwszy argument wyrażenie jest prawdziwe, czy nie. Warunek podaje się przed znakiem zapytania, wartość wyrażenia po znaku zapytania zwracana jest, jeśli warunek ten jest prawdziwy, wartość po dwukropku zwracana jest w przeciwnym wypadku. Oto przykład, w którym zmieniliśmy używaną wcześniej instrukcję if...else na operator ?::

public class app

{

public static void main(String[] args)

{

double srodki = 157.99;

double zadluzenie = 115.99;

String wynik;

wynik = srodki>zadluzenie?"Jesteś wypłacalny.":"O, kurczę!";

System.out.println(wynik);

}

}

Pętle w Javie: for, while, do...while

Po instrukcja warunkowych zajmiemy się pętlami. W Javie, tak jak w JavaScripcie, do dyspozycji mamy pętle for, while oraz do...while.

Oto obowiązująca składnia pętli for:

for (inicjalizacja; warunek; iteracja) {

instrukcje

}

inicjalizacji umieszcza się wyrażenie inicjujące pętli (często jest to inicjalizacja zmiennej - indeksu pętli - na 0). warunek jest sprawdzany przy każdej iteracji pętli i jeśli okazuje się fałszywy, wykonanie pętli jest przerywane. Jeśli warunek jest prawdziwy, treść pętli jest uruchamiana i wykonywane jest wyrażenie iteracja (często jest to po prostu inkrementacja indeksu pętli).

Oto przykład użycia pętli for - sumujemy salda z pięciu kont bankowych z tablicy accounts:

public class app

{

public static void main(String[] args)

{

double accounts[] = {365.55, 789.19, 532.11, 1079.96, 185.19};

double suma = 0;

for (int indeks = 0; indeks < accounts.length; indeks++){

suma += accounts[indeks];

}

System.out.println("Łączna suma z kont wynosi " + suma);

}

}

Wynik będzie następujący:

%java app

Łączna suma z kont wynosi 2952

Java obsługuje także pętlę while. Utworzymy przykład, w którym użyjemy tej pętli do odczytu danych z klawiatury - póki użytkownik nie wpisze słowa quit.

Do czytania znaków z klawiatury można użyć metody System.in.read. Metoda ta czeka, aż wciśnięty zostanie klawisz Enter, od tej chwili Java odczytuje wpisane znaki. Kiedy tę metodę wywołujesz, odczytuje ona następny znak i go zwraca.

Odczytywanie danych rozpoczniemy od utworzenia napisu input, oczekujące dalsze znaki dodawać będziemy do tego napisu po kolejnych wywołaniach metody System.in.read. Następnie będziemy czekać na pojawienie się słowa quit. Użyjemy metody indexOf klasy String do wyszukania tego słowa. Metoda indexOf zwraca położenie początku szukanego napisu lub zwraca -1, jeśli napis nie zostanie znaleziony. Oto początek naszego przykładu:

public class app

{

public static void main(String[] args)

{

String input = "";

while (input.indexOf("quit") < 0) {

.

.

.

}

}

}

Za każdym razem, kiedy użytkownik wciśnie Enter, metoda System.in.read odczytuje wprowadzone przez użytkownika znaki i dopisuje je kolejno do napisu input. Metoda System.in.read wczytuje znaki w postaci odpowiadających im kodów ASCII int, zatem będziemy musieli jawnie je rzutować na typ znakowy operatorem (char).

Twórcy Javy zdawali sobie sprawę, że operacje wejścia/wyjścia są podatne na błędy, wobec czego umożliwili metodzie System.in.read generowanie błędów, które mogą być przez program przechwytywane i obsługiwane. Błędy takie nazywane są błędami przechwytywalnymi lub po prostu wyjątkami. Generację takiego błędu nazywamy generowaniem wyjątku. Kod, który może takie błędy powodować, powinien być umieszczony w specjalnej instrukcji try:

public class app

{

public static void main(String[] args)

{

String input = "";

while (input.indexOf("quit") < 0) {

try {

input += (char) System.in.read();

}

.

.

.

}

}

}

Za blokiem try umieszcza się blok catch, którego zadaniem jest przechwytywanie występujących błędów. Blok catch otrzymuje obiekt klasy Exception, będziemy go nazywać e. Użycie metody printStackTrace tego obiektu pozwala wyświetlić informacje o błędzie, jaki się pojawił, a uzyskany z tej metody tekst przekażemy do strumienia wyjściowego System.err (domyślnie odpowiadającego konsoli):

public class app

{

public static void main(String[] args)

{

String input = "";

while (input.indexOf("quit") < 0) {

try {

input += (char) System.in.read();

} catch (Exception e) {

e.printStackTrace(System.err);

}

}

}

}

Tego nam było trzeba: użytkownik wpisuje tekst, aplikacja go odczytuje, a kiedy w tekście pojawi się słowo quit, aplikacja skończy swoje działanie:

%java app

Cześć!

Świetnie działa.

Ale czy cokolwiek się tu dzieje?

A może by tak wpisać słówko "quit"?

Nieźle - za jednym zamachem poznaliśmy pętlę while i nauczyliśmy się odczytywać dane z klawiatury.

Deklarowanie i tworzenie obiektów

W Javie nowe obiekty najpierw trzeba zadeklarować, potem się je tworzy za pomocą operatora new. Oto przykład tworzenia obiektu klasy String, któremu przekazujemy w konstruktorze tekst Witamy w Javie!:

public class app

{

public static void main(String[] args)

{

String greeting1;

greeting1 = new String("Witamy w Javie!");

.

.

.

Najpierw obiekt greeting1 zadeklarowaliśmy, określiliśmy jego klasę, o później go utworzyliśmy za pomocą operatora new.

Przeciążanie konstruktorów

Klasy mają różne konstruktory, które potrafią obsłużyć różne typy danych. W poprzednim przykładzie konstruktorowi klasy String przekazaliśmy napis, ale równie dobrze moglibyśmy przekazać mu tablicę znaków:

public class app

{

public static void main(String[] args)

{

String greeting1, greeting2, greeting3;

greeting1 = new String("Witamy w Javie!");

char characters[] = {'W', 'i', 't', 'a', 'm', 'y',

' ', 'w', ' ', 'J', 'a', 'v', 'i', 'e', '!'};

greeting2 = new String(characters);

.

.

.

}

}

Konstruktory i metody, które różnią się tylko liczbą i/lub typem argumentów, nazywamy funkcjami przeciążonymi.

Aby funkcję przeciążyć, należy ją po prostu kilkakrotnie zdefiniować, za każdym razem z innym zestawem argumentów.

Przypisywanie obiektów

Jeden obiekt można także innemu przypisywać, używa się do tego operatora przypisania, =:

public class app

{

public static void main(String[] args)

{

String greeting1, greeting2, greeting3;

greeting1 = new String("Witamy w Javie!");

char characters[] = {'W', 'i', 't', 'a', 'm', 'y',

' ', 'w', ' ', 'J', 'a', 'v', 'i', 'e', '!'};

greeting2 = new String(characters);

greeting3 = greeting2;

}

}

Aby ten przykład zakończyć, wydrukujemy utworzone napisy:

public class app

{

public static void main(String[] args)

{

String greeting1, greeting2, greeting3;

greeting1 = new String("Witamy w Javie!");

char characters[] = {'W', 'i', 't', 'a', 'm', 'y',

' ', 'w', ' ', 'J', 'a', 'v', 'i', 'e', '!'};

greeting2 = new String(characters);

greeting3 = greeting2;

System.out.println(greeting1);

System.out.println(greeting2);

System.out.println(greeting3);

}

}

Wynik uzyskamy następujący:

%java app

Witamy w Javie!

Witamy w Javie!

Witamy w Javie!

Tyle o deklarowaniu i tworzeniu obiektów w Javie. Jak widać, jest to podobne do deklarowania i tworzenia zmiennych typów prostych, jednak obiekty można konfigurować przekazując odpowiednie dane konstruktorom ich klas.

Tworzenie w Javie metod

W JavaScripcie tworzyliśmy funkcje. Java jest w pełni obiektowa, więc będziemy tworzyć tylko metody. Metoda to właśnie funkcja, która jednak należy do klasy lub obiektu. Jako przykład utworzymy metodę dodawacz, która doda do siebie dwie liczby i zwróci wynik.

Na początek potrzebujemy dwóch liczb, które będziemy dodawać - pozwolimy użytkownikowi podać je jako parametry wiersza poleceń. Odczytamy je z tablicy args przekazywanej funkcji main, później zamienimy je na liczby całkowite value1 i value2:

public class app

{

public static void main(String[] args)

{

int value1 = Integer.parseInt(args[0]);

int value2 = Integer.parseInt(args[1]);

.

.

.

}

Teraz uzyskane wartości możemy wyświetlić, przekazać je metodzie dodawacz i wyświetlić wynik naszej metody:

public class app

{

public static void main(String[] args)

{

int value1 = Integer.parseInt(args[0]);

int value2 = Integer.parseInt(args[1]);

System.out.println(value1 + " + " + value2 +

" = " + dodawacz(value1, value2));

}

.

.

.

}

Pozostaje jeszcze tylko utworzyć metodę dodawacz. Metodę tę zdefiniujemy jako dostępną publicznie stosując słowo kluczowe public; gdybyśmy użyli słowa kluczowego private (które jest ustawieniem domyślnym), metoda ta byłaby dostępna tylko w swoim obiekcie lub klasie.

Musimy jeszcze określić typ wartości zwracanej przez metodę (jeśli metoda nie ma nic zwracać, określamy jej typ jako void). W końcu podać należy oddzielaną przecinkami listę parametrów w nawiasach po nazwie metody (jeśli metoda nie ma parametrów, nawiasy pozostają puste). Mamy już więc szkielet naszej funkcji dodawacz:

public class app

{

public static void main(String[] args)

{

int value1 = Integer.parseInt(args[0]);

int value2 = Integer.parseInt(args[1]);

System.out.println(value1 + " + " + value2 +

" = " + dodawacz(value1, value2));

}

public static int dodawacz(int int1, int int2)

{

.

.

.

}

}

W treści metody do przekazanych dwóch wartości możemy odwoływać się jak do zwykłych zmiennych, przez ich nazwy, czyli int1 i int2:

public class app

{

public static void main(String[] args)

{

int value1 = Integer.parseInt(args[0]);

int value2 = Integer.parseInt(args[1]);

System.out.println(value1 + " + " + value2 +

" = " + dodawacz(value1, value2));

}

public static int dodawacz(int int1, int int2)

{

return int1 + int2;

}

}

Kiedy użytkownik poda teraz w wierszu poleceń dwie liczby, nasza aplikacja sobie już z nimi poradzi:

%java app 180 120

180 + --> 120[Author:T] = 300

Użycie instrukcji return

Instrukcji return można używać nawet w metodach żadnej wartości nie zwracających - nie podaje się wtedy żadnych parametrów tej instrukcji. Powoduje ona przerwanie wykonywania metody i przekazanie sterowania do miejsca, z którego wywołanie nastąpiło.

Tworzenie klas Javy

Najprostszy przypadek tworzenia klas już widziałeś: aby zrobić jakąkolwiek aplikację, konieczne jest utworzenie klasy głównej aplikacji:

public class app

{

public static void main(String[] args)

{

System.out.println("Witamy w Javie!");

}

}

W ramach przygotowywania się do bardziej złożonych zadań, które czekają w następnym rozdziale, zajmiemy się trochę trudniejszymi przykładami. Utworzymy nową klasę AppFrame opartą na klasie Javy Frame używanej do tworzenia okienek z ramkami (okienko z ramkami ma właśnie nazwy oraz pasek tytułowy). W Javie można używać grafiki na dwa sposoby: można użyć AWT (Zestaw abstrakcyjnych narzędzi okienkowych, Abstract Windowing Toolkit) lub pakietów Swing. My trzymać się będziemy AWT, bo żeby w ogóle zrozumieć mechanizm działania pakietu Swing, trzeba byłoby osobnego rozdziału. Jeśli jednak planujesz poważniej zająć się Javą, polecam Ci przyjrzenie się tym pakietom bliżej.

Oto jak będzie wyglądała metoda main: utworzymy nowy obiekt klasy AppFrame, przekażemy mu w konstruktorze tekst, który pojawić się ma w nowym oknie:

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

.

.

.

}

}

Klasa AppFrame jest tworzona na bazie klasy wbudowanej Javy Frame, możemy użyć metody setSize klasy Frame do ustalenia rozmiaru nowego okienka na 400x200 pikseli, metody show możemy użyć do pokazania nowego okienka:

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.show();

}

}

Tworzenie nowych klas

Klasa AppFrame oparta jest na klasie Javy Frame, co oznacza, że AppFrame będzie miała wszystkie metody tamtej klasy. Metody te zestawiono w tabeli 10.2.

Tabela 7.2.
Metody klasy Frame

Metoda

Opis

void addNotify()

Umożliwia wyświetlanie ramki przez łączenie jej z lokalnym zasobem ekranowym.

protected void finalize()

Wywoływana, kiedy ramka ma być usunięta.

int getCursorType()

Zastąpiona przez Component.getCursor().

static Frame[] getFrames()

Zwraca tablicę zawierającą wszystkie ramki utworzone przez aplikację.

Image getIconImage()

Zwraca obrazek, który ma być wyświetlony jako zminimalizowana ikona.

MenuBar getMenuBar()

Zwraca pasek menu.

int getState()

Zwraca bieżący stan ramki.

String getTitle()

Zwraca tytuł ramki.

boolean isResizable()

Wskazuje, czy użytkownik może zmieniać rozmiar ramki.

protected String paramString()

Zwraca napis z parametrami bieżącej ramki.

void remove(MenuComponent m)

Usuwa podane menu z ramki.

void removeNotify()

Powoduje, że ramki nie daje się wyświetlić.

void setCursor(int cursorType)

Zastąpiona przez Component.setCursor(Cursor).

void setIconImage(Image image)

Określa obrazek, który ma być wyświetlony jako ikona zminimalizowanej ramki.

void setMenuBar(MenuBar mb)

Określa pasek menu ramki.

void setResizable(boolean resizable)

Nakazuje, aby użytkownik mógł zmieniać rozmiar danej ramki.

void setState(int state)

Określa stan ramki.

void setTitle(String title)

Określa tytuł ramki.

Stosując instrukcję class możesz tworzyć swoje własne klasy. Klasa AppFrame tworzona jest na podstawie klasy Frame, zatem zgodnie z terminologią obiektową AppFrame dziedziczy po klasie Frame. Do poinformowania, że jednak klasa oparta jest na innej, używa się słowa kluczowego extends (zwróć uwagę na brak specyfikatora dostępu AppFrame, co oznacza, że dostęp będzie domyślny, zatem użyte zostanie ustawienie private):

import java.awt.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

.

.

.

}

Zauważ, że klasa Frame należy do pakietu AWT, wobec czego konieczne jest zaimportowanie tego pakietu instrukcją java.awt.*;.

Tworzenie konstruktora

Nowa klasa potrzebuje teraz konstruktora - chcemy przekazać konstruktorowi napis, który ma zostać wyświetlony w okienku. Konstruktor tworzy się bardzo prosto, wystarczy zdefiniować metodę o nazwie takiej samej, jak nazwa klasy. Nie podaje się jednakże typu wartości zwracanej przez konstruktor:

import java.awt.*;

import java.awt.event.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

String displayText;

public AppFrame(String text)

{

.

.

.

}

}

Być może zauważyłeś, że metody dodawane do klasy AppFrame nie są zadeklarowane jako static. Dzieje się tak dlatego, że metody te będą używane tylko jako część obiektów, a nie klas. Obiekt klasy AppFrame o nazwie f tworzymy w metodzie main, używamy metod tego obiektu.

Przekazany konstruktorowi tekst przetrzymywać będziemy w zmiennej tekstowej displayText:

import java.awt.*;

import java.awt.event.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

String displayText;

public AppFrame(String text)

{

displayText = text;

}

}

Użycie obiektów graficznych

Następny krokiem jest wyświetlenie tekstu w okienku. Klasa Frame ma metodę paint, która jest wywoływana automatycznie, kiedy tylko okno musi być odtworzone na ekranie. Metoda ta jest przekazywana obiektowi klasy Graphics - obiekt ten nazwiemy g:

import java.awt.*;

import java.awt.event.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

String displayText;

public AppFrame(String text)

{

displayText = text;

}

public void paint(Graphics g)

{

.

.

.

}

}

Metod obiektu Graphics można użyć do rysowania w oknie, zestawiono je w tabeli 7.3.

Tabela 7.3.
Metody klasy Graphics

Metoda

Opis

abstract void clearRect(int x, int y, int width, int height)

Czyści wskazany prostokąt (wypełnia go kolorem tła).

abstract void clipRect(int x, int y, int width, int height)

Obcina prostokąt.

abstract void copyArea(int x, int y, int width, int height, int dx, int dy)

Kopiuje obszar o rozmiarach dx i dy.

abstract Graphics create()

Tworzy nowy obiekt grafiki czyniąc go kopią bieżącego.

Graphics create(int x, int y, int width, int height)

Tworzy nowy obiekt graficzny z nowym układem współrzędnych i obszarem obcinania.

abstract void dispose()

Zwalnia kontekst grafiki.

void draw3DRect(int x, int y, int width, int height, boolean raised)

Wyświetla trójwymiarowy prostokąt.

abstract void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)

Wykreśla łuk kołowy lub eliptyczny.

void drawBytes(byte[] data, int offset, int length, int x, int y)

Wykreśla tekst z tablicy byte.

void drawChars(char[] data, int offset, int length, int x, int y)

Wykreśla tekst z tablicy znakowej.

abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer)

Wykreśla największą możliwą część obrazka, umożliwia określenie koloru tła.

abstract boolean drawImage(Image img, int x, int y, ImageObserver observer)

Wykreśla największą możliwą część obrazka.

abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)

Wykreśla największą możliwą część obrazka, jaka zmieści się w zadanym prostokącie.

abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)

Wykreśla największą możliwą część obrazka skalując go tak, aby zmieścił się w podanym prostokącie.

abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)

Wykreśla możliwie największą część obrazka skalując go, aby zmieścił się w zadanym obszarze.

abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)

Wykreśla możliwie największą część obrazka skalując go, aby pomieścił się w zadanym obszarze powierzchni docelowej.

abstract void drawLine(int x1, int y1, int x2, int y2)

Wykreśla linię w bieżącym kolorze domyślnym od punktu (x1,y1) do punktu (x2,y2).

abstract void drawOval(int x, int y, int width, int height)

Wykreśla elipsę.

abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)

Wykreśla zamknięty wielokąt, którego punktów współrzędne x podano w jednej tablicy, współrzędne y w drugiej.

void drawPolygon(Polygon p)

Wykreśla wielokąt określony podanym obiektem wielokąta.

abstract void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)

Wykreśla ciąg połączonych ze sobą linii.

void drawRect(int x, int y, int width, int height)

Wykreśla prostokąt o zadanych wymiarach i położeniu.

abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)

Wykreśla prostokąt z zaokrąglonymi rogami.

abstract void drawString(AttributedCharacterIterator iterator, int x, int y)

Wykreśla tekst określony iteratorem.

abstract void drawString(String str, int x, int y)

Wykreśla napis podany jako tekst.

abstract void drawString(String str, int x, int y)

Wykreśla tekst podany jako napis.

void fill3DRect(int x, int y, int width, int heith, boolean raised)

Wykreśla i wypełnia zadany prostokąt trójwymiarowy

abstract void fillArc(int x, int y,int width, int height, int startAngle, int arcAngle)

Wypełnia łuk kołowy lub eliptyczny.

abstract void fillOval(int x, int y, int width, int height)

Wypełnia elipsę ograniczoną zadanym prostokątem.

abstract void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)

Wypełnia domknięty wielokąt zdefiniowany przez tablice współrzędnych x i y.

void fillPolygon(Polygon p)

Wypełnia wielokąt określony obiektem Polygon kolorem bieżącym.

abstract void fillRect(int x, int y, int width, int height)

Wypełnia prostokąt.

abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)

Wypełnia prostokąt z zaokrąglonymi rogami.

void finalize()

Wywoływana, kiedy obiekt ma być usunięty (zwolniony).

abstract Shape getClip()

Zwraca obszar obcinania.

abstract Rectangle getClipBounds()

Zwraca obszar otaczający obszaru obcinania.

Rectangle getClipBounds(Rectangle r)

Zwraca prostokąt obcinający wskazanego prostokąta.

Rectangle getClipRect()

Zastąpiona przez getClipBounds().

abstract Color getColor()

Zwraca kolor pierwszego tła bieżącego kontekstu graficznego.

abstract Font getFont()

Zwraca ustawioną bieżąco czcionkę.

FontMetrics getFontMetrics()

Zwraca charakterystykę czcionką bieżącej.

abstract FontMetrics getFontMetrics(Font f)

Zwraca charakterystykę zadanej czcionki.

boolean hitClip(int x, int y, int width, int height)

Zwraca wartość true, kiedy dany obszar przecina prostokąt obszaru obcinania.

abstract void setClip(int x, int y, int width, int height)

Określa obszar obcinania jako podany prostokąt.

abstract void setClip(Shape clip)

Ustawia obszar obcinania na podany kształt.

abstract void setColor(Color c)

Określa kolor podstawowy kontekstu graficznego.

abstract void setFont(Font font)

Ustawia czcionkę kontekstu graficznego.

abstract void setPaintMode()

Określa tryb malowania.

abstract void setXORMode(Color c1)

Określa tryb malowania na tryb XOR.

String toString()

Zwraca obiekt String reprezentujący obiekt Graphics.

abstract void translate(int x, int y)

Przekształca początek układu współrzędnych kontekstu graficznego na nowe współrzędne.

W naszym wypadku do wyświetlenia tekstu w oknie użyjemy metody drawString:

import java.awt.*;

import java.awt.event.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

String displayText;

public AppFrame(String text)

{

displayText = text;

}

public void paint(Graphics g)

{

g.drawString(displayText, 60, 100);

}

}

Zamykanie aplikacji okienkowych

Musimy zrobić jeszcze jedną rzecz: kiedy użytkownik kliknie przycisk Close w prawym górny rogu okna, konieczne będzie obsłużenie zdarzenia zamknięcia okna. W takiej sytuacji w Javie używamy procedury obsługi zdarzenia. Procedura obsługi zdarzenia jest przekazywana zdarzeniu, zatem w chwili zamykania okienka wywołana zostanie funkcja System.exit(0);. Wywołanie to powoduje zakończenie działania programu i przekazuje wartość 0 (czyli poprawne zakończenie) systemowi operacyjnemu.

Szczegółowa obsługa zdarzeń w Javie przekracza zakres niniejszej książki, jednak jakiś prosty przykład się należy. Obiektowi AppFrame przypiszemy procedurę obsługi zdarzenia zamykania okna, a kiedy ono się pojawi, program zostanie zamknięty. Pamiętaj, że jeśli chcesz obsługiwać zdarzenia za pośrednictwem obiektów AWT, musisz zaimportować klasy z pakietu java.awt.event:

import java.awt.*;

import java.awt.event.*;

public class window

{

public static void main(String argv[])

{

AppFrame f = new AppFrame("Tworzymy okienkową aplikację Javy...");

f.setSize(400, 200);

f.addWindowListener(new WindowAdapter() {public void

windowClosing(WindowEvent e) {System.exit(0);}});

f.show();

}

}

class AppFrame extends Frame

{

String displayText;

public AppFrame(String text)

{

displayText = text;

}

public void paint(Graphics g)

{

g.drawString(displayText, 60, 100);

}

}

Wyniki działania tego kodu pokazano na rysunku 7.2. Po uruchomieniu aplikacji pojawia się okienko zawierające nasz tekst.

Rysunek 7.2.

Uruchomienie okienkowej aplikacji Javy

0x01 graphic

Teraz, kiedy mamy już jako takie pojęcie o Javie, czas użyć tej technologii do obsługi XML - ale to już w następnym rozdziale.

Autor jest Amerykaninem więc mamy tu do czynienia z automatyczną skrzynią biegów (przyp. tłum.)

Jeśli w tym miejscu utworzymy zmienną to jest ona widoczna jedynie w pętli. Jest to specyfika języka Java (przyp. tłum.)

36 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

Rozdział 1 Pierwsze kroki (Nagłówek strony)

36 C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r07-01.doc

C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r07-01.doc 1



Wyszukiwarka