Download as pdf or txt
Download as pdf or txt
You are on page 1of 193

Jan Bielecki

Java
od podstaw

Moim przyjacioom Hanne i Rainerowi Langmaack

Spis treci Od Autora Cz I Jzyk Java

Aplikacje i aplety Modyfikowanie apletu Obsugiwanie zdarze Wykonywanie wtkw Obsugiwanie wyjtkw

Cz II

rodowisko rozwojowe

Programowanie manualne Programowanie wizualne

Cz III Podstawy programowania


Leksemy Zmienne Instrukcje Tablice Obiekty Strumienie

Cz IV Programowanie obiektowe
Hermetyzacja Dziedziczenie Interfejsy Konwersje Polimorfizm Kolekcje

Cz V

Programowanie zdarzeniowe

Klasa zdarzeniowa Obsugiwanie zdarze Odtwarzanie pulpitu

Cz VI Programowanie wspbiene
Stany wtkw Priorytety Wtek gwny Tworzenie wtkw Synchronizowanie wtkw Instrukcja synchronizujca
3

Procedury synchronizowane Monitor Impas

Cz VII Programowanie apletw


Opis Wykonanie Otoczenie Grafika Klawiatura Myszka Kursory Obrazy Rozkady Sterowniki Pojemniki Kontrolki Dwiki Animacje Przesyanie Komunikacja Przeczenia

Literatura Sownik terminw Dodatki


A B C D E F Priorytety operatorw Parametry zdarze Klasa uruchomieniowa Styl programowania Typy predefiniowane Operacje i operatory

Od Autora
Nie ulega wtpliwoci, e to co si dzieje wok Javy jest rewolucj. Po dugim okresie przestoju, w ktrym aktywno w zakresie jzykw programowania ograniczaa si do porzdkowania tego, co byo ju znane od kilkunastu lat, pojawi si nowy jzyk, ktry niemal z dnia na dzie zyska aprobat zarwno specjalistw, jak i zwykych uytkownikw Internetu. Swj sukces zawdzicza Java temu, i wysza spod rki zawodowego programisty, e wykorzystano w niej najlepsze pomysy zawarte w jzykach C++, Objective C i Smalltalk oraz e wbudowujc w ni mechanizmy programowania strukturalnego, obiektowego, zdarzeniowego i wspbienego przygotowano grunt pod programowanie rozproszone. Dziki odwanej decyzji implementowania Javy jako jzyka interpretowanego, ktrego kod wynikowy jest wykonywany na Maszynie Wirtualnej, zapewniono przenono programw midzy odmiennymi platformami sprztowymi i systemowymi, i to nie tylko na poziomie kodu rdowego, ale rwnie na poziomie kodu binarnego. Powszechne zaakceptowanie Javy przekroczyo najmielsze oczekiwania jej twrcy Jamesa Goslinga. W lad za wsparciem udzielonym jej przez przez wiodce firmy komputerowe: Sun, Microsoft, IBM, Apple, Oracle, Corel, Netscape, Symantec, Borland, Hewlett Packard, Silicon Graphics, Toshiba, poszy liczne implementacje wizualnych rodowisk Rozwojowych, w tym Cafe i Visual Cafe (Symantec), Open JBuilder (Borland), SuperCede (Asymetrix), Parts for Java (ParcPlace), Visual J++ (Microsoft), Java WorkShop (Sun) i CodeWarrior (Metrowerks). Opracowano wiele wyspecjalizowanych bibliotek jzyka, opublikowano specyfikacj komponentw JavaBeans, implementowano konfigurowaln przegldark HotJava Views oraz wprowadzono na rynek komputery sieciowe JavaStation wyposaone w system operacyjny JavaOS. W deniu do penego upowszechnienia Javy podjto produkcj ukadu scalonego PicoJava, umoliwiajcego wyposaenie w ni takich miniaturowych urzdze konsumenckich jak komrki, faksy i kalkulatory. Niniejsz ksik, zapowiedzian w przedmowie do Java po C++ napisaem dla tych, ktrzy mieli ju styczno z programowaniem, ale nie znaj C++ ani nawet jzyka C. W tej postaci przedkadam j informatykom zafascynowanym nowymi narzdziami Internetu oraz tym wszystkim, ktrzy w lad za wiodcymi orodkami akademickimi porzuc Turbo Pascal, Delphi i Visual Basic, decydujc si na zainwestowanie swego czasu w poznanie narzdzia nastpnego wieku. Lektura tekstu, ktrego kolejnymi czciami s: Jzyk Java, rodowisko rozwojowe, Podstawy programowania, Programowanie obiektowe, Programowanie zdarzeniowe, Programowanie wspbiene, Programowanie apletw i Sownik terminw oraz bardzo wane dla penego poznania jzyka Dodatki, umoliwia agodne wejcie w tematyk programowania w Javie, przygotowujc do lektury mojej nastpnej ksiki pt. Java - programowanie wizualne, powiconej wspczesnej metodyce programowania, wstpnie przedstawionej tu w rozdziale o rodowiskach rozwojowych Jestem przekonany, e niniejszy podrcznik w peni zaspokoi potrzeby tych, ktrzy chc pozna Jav od podstaw oraz e dostarczy obszernego materiau praktycznego nie tylko suchaczom moich wykadw w Politechnice Warszawskiej i Polsko-Japoskiej Wyszej Szkole Technik Komputerowych, ale rwnie tym wszystkim, ktrzy podziel pogld, e gruntowne poznanie Javy jest bardzo dobr inwestycj. Jan Bielecki

Cz I

Jzyk Java

Java jest nowym jzykiem programowania opartym na uznanych jzykach starszej generacji. We wczesnej fazie powstawania bya projektowana jako narzdzie do programowania komunikujcych si ze sob konsumenckich urzdze elektronicznych, ale wkrtce przeksztacono j w narzdzie do programowania aplikacji w sieciach korporacyjnych i w Internecie. Gwn zalet Javy jest przenono programw na p oziomie kodu binarnego. Dziki temu program uruchomiony w pewnym rodowisku operacyjnym (np. Windows) moe by wykonany w dowolnym innym (np. Unix i MacOS). T unikaln waciwo zawdzicza Java temu, i jest jzykiem interpretowanym, a nie kompilowanym. Program rdwy w Javie przygotowuje si za pomoc edytora, a nastpnie poddaje si kompilacji, uruchomieniu i testowaniu. Produktem kocowym jest B-kod Maszyny Wirtualnej (JavaVM) umieszczony w pliku z rozszerzeniem .class. Warunkiem wykonania B-kodu jest wyposaenie platformy programistycznej w emulator Maszyny Wirtualnej: ukad scalony, albo program napisany w rodzimym jzyku platformy. Inwestycja ta jest niewielka i zostaa ju wykonana we wszystkich liczcych si systemach (Windows, Unix, MacOS).

_________________________________________________________________________________________

Aplikacje i aplety
Program napisany w Javie jest aplikacj lub apletem. Aplikacja jest programem samodzielnym, a aplet jest programem zanurzonym w aplikacji, na przykad w przegldarce Netscape. Poniewa przegldarka przydziela apletowi wydzielony obszar okna, nazywany zazwyczaj pulpitem, wic okrelenie aplet utosamia si czsto nie z samym jego programem, ale z tym co ten program wykreli. Z tego powodu maj sens i mog by uywane takie okrelenia jak: napisanie apletu (utworzenie kodu programu) i wywietlenie apletu (uwidocznienie wynikw wykonania kodu).

Struktura programu
Kady program skada si z co najmniej jednego moduu rdowego umieszczonego w pliku. Tekst moduu zapisuje si w ukadzie swobodnym, z dowolnie dodanymi odstpami (spacjami, tabulacjami i zakoczeniami wierszy). Odstpy mona umieszcza poza jednostkami leksykalnymi programu (sowami kluczowymi, identyfikatorami, operatorami i ogranicznikami). Szczegln odmian odstpu stanowi komentarz wierszowy. Zaczyna si on od pary znakw // (skonik, skonik), a koczy w miejscu zakoczenia wiersza. Cay taki napis jest traktowany jak jedna spacja, a wic jest ignorowany.

Aplikacje
Aplikacj jest program skadajcy si z zestawu definicji klas, z ktrych przynajmniej jedna jest publiczna i zawiera publiczn i statyczn funkcj gwn. Nagwek funkcji gwnej ma posta
public static void main(String args[])

Wykonanie aplikacji koczy si w chwili, gdy w funkcji gwnej wykona si instrukcj powrotu
return;

albo gdy z dowolnej procedury (w tym z funkcj i gwnej) wywoa si funkcj exit. Uwaga: Przytoczona instrukcja jest domniemywana przed kad klamr koczc definicj procedury o rezultacie void, a wic jawne jej uycie jest na og zbyteczne. Przykad Najprostsza aplikacja
public class Master {

public statatic void main(String args[]) { } }

Klasa Master jest publiczna. Zawiera ona publiczn i statyczn funkcj gwn. Tu przed klamr koczc definicj funkcji domniemano instrukcj powrotu.

Aplikacje znakowe
Wyniki aplikacji znakowej s wyprowadzane na konsol (ekran monitora), a w rodowisku graficznym (np. Windows 95) do okna konsoli. Nastpujca aplikacja, pokazana podczas wykonania na ekranie Aplikacja znakowa, wyprowadza do okna konsoli napis
Hello, I am JanB.

Ekran Aplikacja znakowa


### textapp.gif

Przykad Aplikacja znakowa


public class Master { public static void main(String args[]) { // wyprowadzenie tekstu na konsol System.out.println("Hello, I am JanB."); } }

Dziki uyciu procedury println, a nie print, zapewniono wyprowadzenie wiersza znakw, a nie tylko znakw zawartych w cudzysowach.

Wstrzymanie zakoczenia aplikacji


Jeli aplikacja znakowa jest wykonywana w rodowisku graficznym, to w chwili jej zakoczenia usuwa si z ekranu okno konsoli. W celu uniknicia towarzyszcego temu "zniknicia" wynikw, zaleca si uycie instrukcji
System.in.read();

Spowoduje to wstrzymanie zamknicia okna konsoli do chwili wprowadzenia z klawiatury dowolnego znaku (np . Enter). W takim jednak wypadku naley nagwek procedury zawierajcej t instrukcj uzupeni fraz
throws IOException

a aplikacj poprzedzi poleceniem


import java.io.IOException

albo
import java.io.*;

Na przykad
import java.io.IOException; public class Master { public static void main(String args[]) { // wyprowadzenie tekstu na konsol System.out.println("Hello, I am JanB."); System.in.read(); } }

Aplikacje graficzne
Wyniki aplikacji graficznej s wyprowadzane do wasnego okna graficznego. Zamknicie okna nie jest na og wystarczajce i w chwili zamknicia aplikacji musi by wywoana funkcja exit. Do komunikowania si aplikacji z oknem graficznym jest wykorzystywany wykrelacz dysponujcy informacjami o waciwociach rodowiska (np. o rodzaju uytej karty graficznej). Dziki temu unika si programowego rozpoznawania rodowiska i umoliwia pisanie programw, ktre mog by wykonywane na dowolnej platformie. Uwaga: Wykrelacz zwizany z oknem mona utworzy dopiero wwczas, gdy okno jest ju wywietlone na ekranie (to jest dopiero po wywoaniu metody show). Nastpujca aplikacja, pokazana podczas wykonania na ekranie Aplikacja graficzna, wykrela w oknie napis
Hello, I am JanB.

Ekran Aplikacja graficzna


### graphapp.gif import java.io.IOException; import java.awt.*; public class Master { public static void main(String args[]) throws IOException { // utworzenie okna graficznego Frame frame = new MyFrame("Results"); // okrelenie rozmiarw okna frame.resize(160, 80); // wywietlenie okna frame.show(); // utworzenie wykrelacza // komunikujcego si z oknem Graphics gDC = frame.getGraphics(); // wykrelenie tekstu // za porednictwem wykrelacza gDC.drawString("Hello, I am JanB.", 10, 20); System.out.println("Press Enter to exit!); System.in.read(); System.exit(0); } } class MyFrame extends Frame { MyFrame(String caption) { // przekazanie nazwy okna klasie Frame super(caption); } // obsuga zdarzenia WINDOW_DESTROY // generowanego w chwili zamknicia okna public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { hide(); // ukrycie okna dispose(); // zniszczenie okna return true; } else return super.handleEvent(evt); } }

Program aplikacji skada si z definicji klas Master i MyFrame. Klasa Master zawiera definicj funkcji gwnej, a klasa MyFrame wywodzi si z klasy bibliotecznej Frame. Poza klas Frame, aplikacja posuguje si klas biblioteczn Graphics. Kod tych klas jest zawarty w pakiecie java.awt, wczonym do programu za pomoc deklaracji importu 8

import java.awt.*;

W celu uniknicia przedwczesnego zamknicia aplikacji, wywoanie funkcji exit poprzedzono wykonaniem instrukcji
System.in.read();

Aplety
Apletem jest program skadajcy si z zestawu definicji klas, z ktrych przynajmniej jedna jest publiczna i wywodzi si (extends) od klasy Applet. Tak zdefiniowana klasa apletowa zawiera w oglnym wypadku procedury init, start, paint, stop, destroy stanowice jej metody. Wymienione metody s wywoywane przez przegldark w podanej kolejnoci. Metoda init oraz metoda destroy jest wywoywana jednokrotnie. Metody start, stop i paint mog by wywoywane wielokrotnie. Uwaga: Program apletu nie musi zawiera takich typowych wywoa System.in.read() i System.exit(0). W najprostszym przypadku wystarcza zdefiniowanie w aplecie tylko metody paint. Jest ona wywoywana wkrtce po wykonaniu metody init, a take w kadej sytuacji gdy zaistnieje potrzeba odtworzenia pulpitu apletu (na przykad po zasoniciu i odsoniciu go przez pewne okno). Aby przegldarka moga wywietli aplet, naley przekaza jej opis apletu. Uproszczony do minimum ma on posta
<applet code = Nazwa.class width = Szeroko height = Wysoko > </applet>

w ktrej Nazwa jest nazw klasy apletowej, a Szeroko i Wysoko okrelaj poziomy i pionowy rozmiar apletu. Nastpujcy aplet, pokazany podczas wykonania na ekranie Pozdrowienie, wykrela na swoim pulpicie napis
Hello, I am JanB.

Ekran Pozdrowienie
### hello.gif <applet code=Master.class width=200 height=80> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Font font; // czcionka public void init() { font = new Font("TimesRoman", // krj Font.BOLD | Font.ITALIC, // styl 24); // rozmiar } public void paint(Graphics gDC) { gDC.setFont(font); // wstaw do wykrelacza gDC.drawString("Hello, I am JanB.", 10, 50); } }

Program apletu skada si z definicji klasy Master wywodzcej si od klasy Applet. Klasa Master zawiera definicje metod init i paint. Metoda init jest wywoywana jednokrotnie, a metoda paint jest wywoywana co najmniej jeden raz. 9

W metodzie init przygotowano czcionk do wykrelenia tekstu. W metodzie paint jest ona wstawiana do wykrelacza, dziki czemu zapowiedziany napis jest wykrelany czcionk TimesRoman, pogrubion (BOLD) i pochylon (ITALIC), o rozmiarze 24 punktw (1 punkt drukarski to okoo 1/72 cala).

Aplikacje a aplety
Podzia na aplikacje i aplety jest umowny. Nastpujcy program jest zarwno apletem jak i aplikacj.
<applet code=Master.class width=100 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; import java.io.IOException; public class Master extends Applet { public static void main(String args[]) { System.out.println("I am an application."); System.in.read(); System.exit(0); } public void paint(Graphics gDC) { gDC.drawString("I am an applet.", 10, 10); } }

W zalenoci od sposobu potraktowania, program wyprowadza napis


I am an applet.

albo
I am an application.

_________________________________________________________________________________________

Modyfikowanie apletu
Kada klasa definiujca aplet jest opisem rodziny obiektw. Jeli podklasa (klasa pochodna) wywodzi si od innej klasy, to jej obiekty skadaj si ze skadnikw jej nadklasy (klasy bazowej) oraz dodatkowo z wasnych skadnikw podklasy. Jeli w podklasie wystpuje metoda o identycznej sygnaturze jak pewna metoda nadkla sy, to przedefiniowuje ona metod nadklasy. Dziki temu, definiujc podklas wystarczy poda w niej tylko metody przedefiniowujce oraz metody dodatkowe. Uwaga: Metoda przedefiniowujca nie moe by bardziej-prywatna ni metoda przedefiniowywana. W szczeglnoci, jeli metoda przedefiniowywana jest publiczna, to metoda przedefiniowujca take musi by publiczna. Nastpujcy aplet, pokazany podczas wykonania na ekranie Modyfikowanie, ilustruje zasad modyfikowania apletu przez zastosowanie przedefiniowania metod. Ekran Modyfikowanie
### modify.gif <applet code=Master.class width=200 height=80> </applet> ============================================== // Plik Master.java import java.applet.*; import java.awt.*; public class Master extends Applet { Font font; public void init()

// czcionka

10

{ font = new Font("TimesRoman", // krj Font.BOLD | Font.ITALIC, // styl 24); // rozmiar } public void paint(Graphics gDC) { gDC.setFont(font); // wstaw do wykrelacza gDC.drawString("Hello, I am JanB.", 10, 50); } } // Plik Master2.java import java.applet.*; import java.awt.*; public class Master2 extends Master { public void init() { font = new Font("Helvetica", Font.BOLD, 18); } }

// krj // styl // rozmiar

Klasa Master2 wywodzi si od klasy Master, a wic porednio od klasy Applet. Klasa Master2 zawiera wszystkie skadniki apletu Master (w tym jego metod paint), ale przedefiniowuje jego metod init. Dlatego wykonanie apletu Master2 powoduje wykrelenie napisu
Hello, I am JanB.

18 pt czcionk Helvetica, a nie 24 pt czcionk TimesRoman.

_________________________________________________________________________________________

Obsugiwanie zdarze
Od czasu pojawienia si Javy, mona zauway powszechne wyposaanie stron WWW w interakcyjne aplety, reagujce na takie zdarzenia zewntrzne jak kliknicie przyciskiem myszki albo nacinicie klawisza klawiatury. Obsugiwanie zdarze zewntrznych odbywa si za pomoc predefiniowanych metod klas komponentowych (m.in. Panel, Applet), opisujcych takie obiekty oblicza graficznego (Graphical interface) jak etykiety (Label), przyciski (Button), ramki (Frame), itp. Obsuga domniemana polega zazwyczaj na zignorowaniu zdarzenia, dlatego w celu dostarczenia wasnej obsugi zdarzenia zewntrznego, naley dokona przedefiniowania metody domniemanej. W szczeglnoci, poniewa w klasie komponentowej Applet obsuga przecigania kursora myszki jest okrelona przez metod
public boolean mouseDrag(Event evt, int x, int y) { return false; // zignoruj zdarzenie }

wic w celu dostarczenia wasnej obsugi wystarczy przedefiniowa metod mouseDrag. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Wykrelanie z rki, ilustruje zasad obsugiwania zdarze. Ekran Wykrelanie z rki
### scribe.gif <applet code=Master.class width=200 height=80> </applet> ============================================== import java.applet.*;

11

import java.awt.*; public class Master extends Applet { int xPos, yPos; Graphics gDC; public void init() { gDC = getGraphics(); } public boolean mouseDown(Event evt, int x, int y) { xPos = x; yPos = y; return true; } public boolean mouseDrag(Event evt, int x, int y) { gDC.drawLine(xPos, yPos, x, y); xPos = x; yPos = y; return true; } public boolean mouseUp(Event evt, int x, int y) { repaint(); return true; } public void paint(Graphics gDC) { gDC.drawString("Drag mouse to draw!", 10, 20); } }

Wykonanie metody init powoduje utworzenie wykrelacza zwizanego z pulpitem apletu. Wykonanie metody paint powoduje wykrelenie zachty do wykrelania linii metod przecigania kursora myszki. Wykonanie metody mouseDown powoduje zapamitanie wsprzdnych punktu nacinicia przycisku myszki. Kadorazowe wykonanie metody mouseDrag powoduje wykrelenie odcinka czcego punkt poprzedni z biecym. Wykonanie metody mouseUp powoduje wywoanie metody repaint. Wywoanie metody repaint powoduje, e po zakoczeniu wykonywania metody z ktrej j wywoano (tu metody mouseUp), nastpi wywoanie metody update (domylnie wyczyszczenie pulpitu i wywoanie metody paint).

_________________________________________________________________________________________

Wykonywanie wtkw
Oprogramowanie ruchomej grafiki wymaga utworzenia co najmniej jednego dodatkowego wtku: niezalenego od obsugi zdarze, przepywu sterowania przez B-kod programu. W celu ustanowienia wtku naley utworzy obiekt klasy Thread oraz okreli w jakiej klasie znajduje si metoda run, okrelajca czynnoci wtku. Uwaga: Klasa zawierajca metod run musi implementowa interfejs Runnable. Fakt ten wyraa si za pomoc sowa kluczowego implements. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Wykonywanie wtkw, ilustruje zasad programowania wspbienego z wykorzystaniem wtkw. Ekran Wykonywanie wtkw
### thread.gif <applet code=Master.class width=100 height=100> </applet> ===============================================

12

import java.applet.*; import java.awt.*; public class Master extends Applet { Thread thread; Graphics gDC; Color backGround; Circle circle; public void init() { gDC = getGraphics(); backGround = getBackground(); circle = new Circle(gDC, backGround); thread = new Thread(circle); thread.start(); } } class Circle implements Runnable{ Graphics gDC; Color backGround; Circle(Graphics gdc, Color back) { gDC = gdc; backGround = back; } public void run() { for(int i = 0; i < 100 ; i++) { gDC.setColor(Color.black); gDC.drawOval(i, i, i/2, i/2); try { Thread.currentThread().sleep(100); } catch(InterruptedException e) { } gDC.setColor(backGround); gDC.drawOval(i, i, i/2, i/2); } } }

Wykonanie instrukcji
circle = new Circle(gDC, backGround);

powoduje utworzenie obiektu klasy Circle, ktrego skadnikiem jest metoda run. Wykonanie instrukcji
thread = new Thread(circle);

powoduje utworzenie obiektu zarzdzajcego wtkiem. Wykonanie instrukcji


thread.start();

powoduje utworzenie wtku realizowanego przez metod run (tu: wykrelenie okrgu poruszajcego si po przektnej apletu). Zakoczenie wykonywania metody run powoduje zniszczenie wtku.

_________________________________________________________________________________________ 13

Obsugiwanie wyjtkw
Podczas wykonywania programu mog wystpi sytuacje wyjtkowe: dzielenie przez 0, dostarczenie danej o zym formacie, albo napotkanie koca pliku. Z miejsca wystpienia sytuacji wyjtkowej jest wysyany wyjtek: obiekt szczegowo opisujcy sytuacj wyjtkow. Dziki temu, e wyjtek moe by przechwycony, a sytuacja wyjtkowa obsuona, stwarza si szans wyjcia z powstaej sytuacji wyjtkowej i umoliwia kontynuowanie wykonywania programu. Do jawnego wysyania wyjtkw suy instrukcja throw, a do przechwytywania i obsugiwania wyjtkw instrukcja try. Jeli wywoanie pewnej procedury moe spowodowa wysanie wyjtku, to wymaga si, aby zawarto je w bloku instrukcji try, albo aby w nagwku procedury wywoujcej umieszczono fraz throws wyszczeglniajc ten wyjtek. Uwaga: Wyszczeglnienie nazwy wyjtku we frazie throws metody przedefiniowujcej jest dozwolone tylko wwczas, gdy taka nazwa wystpuje albo moe wystpi we frazie throws metody przedefiniowywanej. Na przykad
int readByte(String fileName) throws IOException { try { FileInputStream inp = new FileInputStream(fileName); try { return inp.read(); } catch(IOException e) { System.out.println("File " + fileName + " empty or read error"); throw new IOException(); } } catch(FileNotFoundException e) { System.out.println("File " + fileName + " does not exist"); return -1; } }

Podczas wykonania operacji


new FileInputStream(fileName)

moe zosta wysany wyjtek klasy FileNotFoundException albo wyjtek klasy IOException. Wysanie pierwszego z nich jest obsuone przez zewntrzn fraz catch, a o moliwoci wysania drugiego informuje fraza throws. Podczas wykonywania operacji
inp.read()

moe by wysany wyjtek klasy IOException. Wyjtek ten jest obsuony przez wewntrzn fraz catch. Poniewa w ciele funkcji readByte uyto instrukcji
throw new IOException();

wic w jej nagwku musi wystpi fraza throws.

Osabienie wymaga
Wymaganie uycia frazy throws nie dotyczy wyjtkw kategorii RuntimeException, w tym wyjtkw ArithmeticException NumberFormatException IndexOutOfBoundsException (bd operacji arytmetycznej) (zy format liczby) (indeks poza zakresem) 14

NegativeArraySizeException NullPointerException oraz wyjtkw kategorii Error, w tym wyjtkw OutOfMemoryError StackOverflowError ClassFormatError NoClassDefFoundError

(ujemny rozmiar tablicy) (odwoanie przez odniesienie puste)

(brak pamici operacyjnej) (przepenienie stosu) (bd reprezentacji klasy) (brak definicji klasy)

ale dotyczy wyjtkw kategorii IOException zwizanych z wykonywaniem operacji wejcia-wyjcia, w tym m.in. wyjtkw EOFException FileNotFoundException InterruptedIOException Przykad Obsugiwanie wyjtkw
import java.io.*; public class Master { public static void main(String args[]) throws IOException { open("SOURCE", 0); System.in.read(); } static void open(String fileName, int value) { // nastpna instrukcja jest poprawna, mimo i // nie przewidziano dla niej obsugi wyjtku // ArithmeticException System.out.println(1 / value); // ... FileInputStream stream; // nastpna instrukcja jest bdna, poniewa // nie przewidziano dla niej obsugi wyjtkw // FileNotFoundException i IOException stream = new FileInputStream(fileName); } }

(koniec pliku) (brak pliku) (przerwanie przesania)

Mimo i podczas wykonywania instrukcji


System.out.println(1 / value);

moe by wysany wyjtek ArithmeticException, nie stawia si wymagania obsuenia go. Podczas wykonania instrukcji
stream = new FileInputStream(fileName);

moe zosta wysany wyjtek FileNotFoundException oraz wyjtek IOException. Poniewa aden z tych wyjtkw nie zosta obsuony, wic przytoczony program jest bdny. Jednym ze sposobw poprawienia bdu jest uycie instrukcji try dla wyjtku FileNotFoundException oraz umieszczenie w nagwku funkcji open frazy throws wyszczeglniajcej wyjtek IOException.
import java.io.*; public class Master { public static void main(String args[]) throws IOException { open("SOURCE", 0); System.in.read(); }

15

static void open(String fileName, int value) throws IOException { try { System.out.println(1 / value); } catch(ArithmeticException e) { System.out.println("Division by 0"); System.exit(-1); // przerwanie wykonywania } // ... FileInputStream stream; try { stream = new FileInputStream(fileName); } catch(FileNotFoundException e) { System.out.println("File" + fileName + " not found"); System.exit(-2); } } }

Poniewa z nagwka funkcji open wynika, e moe by z niej wysany wyjtek klasy IOException, wic uwzgldniono to w funkcji main. Jako metod obsugi przyjto uycie frazy throws wyszczeglniajcej ten wyjtek. W celu usunicia z nagwka funkcji open frazy throws, naleaoby instrukcj
try { stream = new FileInputStream(fileName); } catch(FileNotFoundException e) { System.out.println("File" + fileName + " not found"); System.exit(-2); }

zastpi na przykad instrukcj


try { stream = new FileInputStream(fileName); } catch(FileNotFoundException e) { System.out.println("File" + fileName + " not found"); System.exit(-2); } catch(IOException e) { System.exit(-3); }

16

Cz II

rodowisko rozwojowe

Do uruchomienia zamieszczonych w ksice programw uyto rodowiska Rozwojowego Cafe (wersja 1.51) skadajcego si z wbudowanego edytora, kompilatora i uruchamiacza. rodowisko to, opracowane przez firm Symantec, uzyskao w kategorii narzdzi do programowania w Internecie tytu Najlepszego Produktu Roku (The best product for Web Development). Poniewa na tytu ten w peni zasuguje, a jest znacznie lepsze ni inne porwnywalne produkty (np. Visual J++), wic mona je z przekonaniem poleci kademu, komu zaley na komfortowym programowaniu w Javie.

Wywoanie rodowiska
Po wywoaniu rodowiska Cafe pojawia si informacja o jego wersji. Jest ona wywietlana take po wydaniu polecenia Help/About. Na ekranie Winieta Cafe pokazano ekran identyfikujcy rodowisko. Ekran Winieta Cafe
### welcome.gif

Tworzenie programw
rodowisko Cafe umoliwia tworzenie programw nie tylko w sposb tradycyjny, to jest metod manualnego generowania kodu, ale rwnie zawiera mechanizmy umoliwiajce programowanie wizualne, dostpne w takich rodowiskach drugiej generacji jak Visual Cafe Java WorkShop Open JBuilder SuperCede CodeWarrior Parts for Java (Symantec) (Sun) (Borland) (Asymetrix) (Metrowerks) (ParcPlace)

Programowanie wizualne jest bardzo atrakcyjne dla tych, ktrzy nie chc nadmiernie zagbia si w tajniki programowania w Ja vie, ale chc w krtkim czasie uzyska poprawnie dziaajcy i wcale niebanalny program.

_________________________________________________________________________________________

Programowanie manualne
Programowanie manualne polega na rcznym przygotowaniu skadnikw programu, a nastpnie utworzeniu z nich wykonywalnego programu wynikowego. Przy takim postpowaniu wyposaenie programu w oblicze graficzne (graphical interface) jest niekiedy do uciliwe, ale czyni program krtszym i wydajniejszym.

Edycja dokumentu
Wydanie polecenia File/New powoduje utworzenie okna edycyjnego, w ktrym mona przygotowa modu rdowy albo dokument HTML. Po zakoczeniu edycji modu albo dokument naley zapamita w pliku. Jeli tekst jest moduem rdowym, ktry zawiera klas publiczn Class, to nazw pliku musi by Class.java. Jeli jest dokumentem HTML, to nazwa pliku powinna mie rozszerzenie .html. Uwaga: Jeli program zawiera tylko jedn klas publiczna Class, to zaleca si umieszczenie dokumentu HTML w pliku Class.html.

Utworzenie projektu
W celu utworzenia projektu naley wyda polecenie Project/New. Spowoduje to wywietlenie okna dialogowego Project Express pokazanego na ekranie Nazwanie projektu. Ekran Nazwanie projektu
### name.gif

17

W klatce Project Name naley wwczas poda Nazw projektu, a przez zapoznanie si z list Directories upewni, e plik projektu zostanie zapamitany w uprzednio utworzonym katalogu. Po naciniciu przycisku Next wywietli si okno pokazane na ekranie Okrelenie typu projektu. Ekran Okrelenie typu projektu
### type.gif

W oknie tym naley poda czy tworzony program jest aplikacj czy apletem (lista Target Type), a przez wybranie nastawy Project Settings zdecydowa si na to, czy program wynikowy bdzie uruchamiany (Debug) czy dystrybuowany (Release). Po naciniciu przycisku Next wywietli si okno pokazane na ekranie Dodaj pliki. W oknie tym naley poda jakie pliki wchodz w skad projektu. Odbywa si to przez dwukliknicie elementu listy File Name, albo przez zaznaczenie jej eleme ntu i nacinicie przycisku Add. Uwaga: Jeli projekt dotyczy apletu, to do projektu naley rwnie wczy plik zawierajcy dokument HTML. Ekran Dodaj pliki
### addfile.gif

Po naciniciu przycisku Next wywietli si okno pokazane na ekranie Ustawienia pocztkowe. W jego klatce Class Path mona poda nazwy katalogw, w ktrych maj by poszukiwane pliki wczone do projektu. Uwaga: Jeli klasy programu nale do pakietu domylnego (w pliku rdowym nie ma polecenia package), to klatka Class Path moe pozosta pusta). Ekran Ustawienia pocztkowe
### settings.gif

Otwarcie projektu
Uprzednio utworzony projekt moe by nastpnie otwarty, a przetwarzanie programu moe by wwczas kontynuowane. W celu otwarcia projektu naley wyda polecenie Project/Open. Spowoduje to wywietlenie okna Open Project, pokazanego na ekranie Otwarcie projektu. W jego klatce File Name, z uwzgldnieniem katalogu okrelonego przez list Folders, naley poda nazw uprzednio utworzonego projektu. Ekran Otwarcie projektu
### openprj.gif

Modyfikowanie projektu
W celu zmodyfikowania otwartego (a wic ju istniejcego) projektu, naley wyda polecenie Project/Edit albo Project/Settings. Spowoduje to wywietlenie znanych ju okienek dialogowych, w ktrych mona dokona modyfikacji projektu (np. przeksztaci aplikacj w aplet, lub odwrotnie).

Konfigurowanie pulpitu
Przed, albo po utworzeniu projektu mona skonfigurowa pulpit rodowiska. Mona to wykona za pomoc polece menu Window. W szczeglnoci wydanie polece Views, Build i Debug spowoduje wywietlenie okienek pokazanych na ekranie Okienka rodowiska. Uwaga: Operacje na okienku Views odbywaj si przez przecignicie ikony, a operacje na okienku Builds i Debug odbywaj si przez kliknicie. Ekran Okienka rodowiska
### desktop.gif

18

Kompilowanie moduu
W celu skompilowania moduu rdowego naley w okienku Build klikn ikon Compile. Jeli modu zawiera bdy, to kompilator wywietli je w odrbnym oknie. Dwukliknicie wiersza wyszczeglniajcego bd spowoduje wywietlenie tego fragmentu programu, w ktrym bd ten wykryto. Uwaga: Skompilowanie pojedynczego moduu jest wykonywane rzadko. Zazwyczaj od razu przystpuje si do zbudowania programu. W takim wypadku Cafe kompiluje tylko te moduy, ktre zostay zmienione w okresie od poprzedniej ich kompilacji. Na ekranie Niepomylna kompilacja pokazano skutek skompilowania programu zawierajcego bdy skadniowe. Ekran Niepomylna kompilacja
### badcomp.gif

Budowanie programu
W celu zbudowania programu naley w okienku Build klikn ikon Build albo Rebuild All. Nastpi wwczas skompilowanie wszystkich moduw wchodzcych w skad projektu i utworzenie B-kodu programu. Sygnalizowanie ewentualnych bdw skadniowych odbywa tak jak podczas kompilowania moduu. Budowanie moe dotyczy tylko takiego programu, w ktrym wyrniono modu gwny (plik zawierajcy opis apletu albo program z funkcj main). Ma to istotne znaczenie zwaszcza wwczas, gdy w skad projektu wchodzi wicej ni jeden modu rdowy albo dokument HTML. W takim wypadku naley w oknie projektu klikn lewym przyciskiem myszki nazw moduu, a nastpnie klikn j prawym i wybra opcj Mark as Main. Wykonanie tej operacji pokazano na ekranie Zdefiniowanie moduu gwnego. Ekran Zdefiniowanie moduu gwnego
### main.gif

Uwaga: Podczas kompilowania lub budowania programu pojawia si niekiedy komunikat


Access violation

Ten niepokojcy komunikat, ktremu nie towarzyszy adna diagnoza o przyczynie bdu, jest najczciej wywoany literwk w nazwie klasy, na przykad napisaniem
new DEbug();

zamiast
new Debug();

albo doprowadzeniem do wystpienia niezrwnowaonych nawiasw klamrowych. Na ekranie Zagroenie bezpieczestwa pokazano sytuacj, ktra doprowadzia do powstania rozpatrywanego komunikatu. Ekran Zagroenie bezpieczestwa
### security.gif

Dostarczenie argumentw
Jeli program jest aplikacj, to zazwyczaj oczekuje argumentw skojarzonych z parametrami funkcji main. W celu ich dostarczenia, naley wyda polecenie Project/Arguments. Spowoduje to wywietlenie dialogu Run arguments, pokazanego na ekranie Dostarczenie argumentw. W okienku dialogu mona poda wymagane argumenty aplikacji. Ekran Dostarczenie argumentw
### giveargs.gif

Wykonanie programu
19

W celu wykonania programu naley w okienku Build klikn ikon Excecute Program. Jeli program jest aplikacj, to nastpi wwczas podjcie wykonania publicznej i statycznej funkcji main. Jeli jest apletem, to nastpi zinterpretowanie dokumentu HTML wchodzcego w skad projektu i wywietlenie opisanych w nim apletw. Jeli po aktywowaniu programu nastpi wyadowanie i zaadowanie Cafe, bez moliwoci zaobserwowania czegokolwiek, to zapewne 1) 2) 3) 4) 5) Program jest aplikacj, ale nie wyposaono go w statyczn i publiczn funkcj main zawart w klasie, ktra jest publiczna. Program jest aplikacj, ktra wyprowadza wyniki na konsol, ale nie zapewniono moliwoci obejrzenia konsoli (zazwyczaj pomaga System.in.read()). Program jest apletem, ale nie zawiera publicznej nadklasy klasy Applet. Program jest apletem, ale jego nazwa podana w opisie apletu (np. Master.class) nie wynika z nazwy klasy apletu (np. Master). Wykonanie programu doprowadzio do wysania nieobsuonego wyjtku.

Jeli po aktywowaniu apletu zniknie rodowisko Cafe, ale nic si nie wywietli, to najprawdopodobniejsz tego przyczyn jest bd w opisie apletu, na przykad brak zamykajcego nawiasu ktowego w opisie apletu albo bdna nazwa p arametru (np. lenght zamiast length). Uwaga: W systemie Windows 95 naley w takim wypadku nacisn klawisze Ctrl-Alt-Del, wyszuka program Appletviewer, a nastpnie wyda polecenie End Task. Spowoduje to powrt do rodowiska Cafe. Jeli po wykonaniu aplikacji nie pojawi si oczekiwany napis, to zapewne nie spowodowano wymiecenia bufora wyjciowego konsoli, tj. zapomniano, e po wykonaniu sekwencji instrukcji
System.out.print(exp);

naley wykona instrukcj


System.out.println();

Uruchomienie programu
Podczas uruchamiania programw posugiwaem si wasn klasa uruchomieniow, przytoczon w Dodatku Klasa uruchomieniowa. Okazaa si ona bardzo przydatna, dlatego szczerze zachcam do jej uycia. Ci, ktry oczekuj wikszego komfortu mog uy uruchamiacza wbudowanego w Cafe. Posugiwanie si nim jest na tyle proste, e nie wymaga dodatkowych wyjanie. Na ekranie Uruchamianie pokazano wykonanie programu posugujcego si klas Debug. Wywietlenie jego moduu rdowego zapewniono dziki aktywowaniu dodatkowej kopii rodowiska Cafe, w ktrym otwarto plik zawierajcy ten modu. Ekran Uruchamianie
### debugger.gif

Przykad Wysanie nieobsuonego wyjtku


import java.io.IOException; import java.awt.*; public class Master { static { new Debug(); // por. Dodatek Klasa uruchomieniowa } public static void main(String args[]) { div(1, 0); System.in.read(); } static void div(int num, int den) { System.out.println(num / den); } }

20

Wykonanie programu powoduje wysanie wyjtku klasy ArithmeticException, a na skutek nie obsuenia go, wyprowadzenie do okna konsoli napisu
java.lang.ArithmeticException: / by zero at Master.div(Master.java:17) at Master.main(Master.java:12)

Z analizy napisu wynika, e bd " dzielenie przez 0" (/ by zero) wystpi w 17. wierszu funkcji sub, wywoanej z 12. wiersza funkcji main. W wykryciu bdu okazaa si pomocna klasa Debug opisana w Dodatku Klasa uruchomieniowa.

________________________________________________________________________________________

Programowanie wizualne
Programowanie wizualne polega na uyciu generatora do wytworzenia kodu obsugujcego graficznie zaprojektowane oblicze programu. Wygenerowanie programu jest atwe, ale na og czyni program duszym i mniej wydajnym. Nastpujcy aplet, utworzony za pomoc generatora programw, pokazany podczas wykonania na ekranie Programowanie wizualne, umoliwia zapoznanie si z kolorami o podanych skadnikach RGB (red, green, blue). Ekran Programowanie wizualne
### visual.gif

Przykad Program wygenerowany


<HTML> <HEAD><TITLE> Master </TITLE></HEAD> <BODY> <APPLET CODE="Master.class" WIDTH=283 HEIGHT=190> </APPLET> </BODY> </HTML> ================================================= import java.applet.*; import java.awt.*; public class Master extends Applet { private int red, green, blue; public void init() { super.init(); //{{INIT_CONTROLS setLayout(null); resize(303, 133); panel = new Panel(); panel.setLayout(null); add(panel); panel.reshape(14, 39, 66, 43); redEdit = new TextField(7); add(redEdit); redEdit.reshape(106, 18, 58, 20); greenEdit = new TextField(7); add(greenEdit); greenEdit.reshape(106, 54, 58, 20); blueEdit = new TextField(7); add(blueEdit); blueEdit.reshape(106, 90, 58, 20); redLabel = new Label("Red"); add(redLabel); redLabel.reshape(161, 20, 47, 17); greenLabel = new Label("Green"); add(greenLabel); greenLabel.reshape(161, 56, 47, 17); blueLabel = new Label("Blue"); add(blueLabel); blueLabel.reshape(161,92,47,17); exitButton = new Button("Exit");

21

exitButton.setFont(new Font("Helvetica", Font.BOLD,10)); add(exitButton); exitButton.reshape(232, 3, 67, 19); //}} } public void paint(Graphics gDC) { Rectangle b = panel.bounds(); gDC.drawRect(b.x-1, b.y-1, b.width+1, b.height+1); } public boolean handleEvent(Event evt) { if (evt.id == Event.ACTION_EVENT && evt.target == redEdit) { redEnter(evt); return true; } else if (evt.id == Event.ACTION_EVENT && evt.target == greenEdit) { greenEnter(evt); return true; } else if (evt.id == Event.ACTION_EVENT && evt.target == blueEdit) { blueEnter(evt); return true; } else if (evt.id == Event.ACTION_EVENT && evt.target == exitButton) { clickedExitButton(); return true; } return super.handleEvent(evt); } //{{DECLARE_CONTROLS Panel panel; TextField redEdit; TextField greenEdit; TextField blueEdit; Label redLabel; Label greenLabel; Label blueLabel; Button exitButton; //}} public void clickedExitButton() { // to do: put event handler code here. System.exit(0); } public void redEnter(Event evt) { // to do: put event handler code here. showColor(red = rgb(evt), green, blue); } public void greenEnter(Event evt) { // to do: put event handler code here. showColor(red, green = rgb(evt), blue); } public void blueEnter(Event evt) { // to do: put event handler code here. showColor(red, green, blue = rgb(evt)); } int rgb(Event evt) { return Integer.parseInt((String)evt.arg); } void showColor(int r, int g, int b) { Color color = new Color(r, g, b);

22

panel.setBackground(color); panel.repaint(); } }

Generowanie programu
W celu wywoania generatora naley wyda polecenie Tools/AppExpress. Spowoduje to wywietlenie okna dialogowego pokazanego na ekranie Generator programu. Bezporednio po wywoaniu generatora jest w nim wyrniony przycisk Application Type oraz zwizany z nim zestaw przyciskw Applications. Umoliwiaj one okrelenie, czy program ma by apletem czy aplikacj. Uwaga: Dalszy opis dotyczy generowania apletu zdefiniowanego przez klas o arbitralnie wybranej nazwie Master. Ekran Generator programu
### apptype.gif

Po naciniciu przycisku Select Directory wywietli si okno pokazane na ekranie Wybranie katalogu. Naley w nim okreli nazw katalogu, w ktrym ma by wygenerowany program. Ekran Wybranie katalogu
### catalog.gif

Po naciniciu przycisku Miscellaneous wywietli si okno pokazane na ekranie Nazwa projektu. Naley w nim poda nazw projektu (Master). Odbywa si to przez wypenienie klatki Project Name Ekran Nazwa projektu
### prjname.gif

Po naciniciu przycisku Finish nastpi wygenerowanie programu aplikacji.

Projektowanie oblicza
W celu zaprojektowania oblicza graficznego programu naley wyda polecenie Resource/Open, a w wywietlonym wwczas oknie dialogowym wybra nazw pliku z rozszerzeniem .rc (Master.rc). Spowoduje to wywietlenie okna, w ktrym po klikniciu pozycji Form i Master.init pojawi si ramka, pokazana na ekranie Pulpit apletu. Ekran Pulpit apletu
### pulpit.gif

Zapenienie ramki sterownikami odbywa si za pomoc narzdzi zawartych w ramce narzdziowej. Po klikniciu narzdzia i przecigniciu kursora w obrbie pulpitu nastpuje wykrelenie sterownika. Zestawy sterownikw mog by rozmieszczane na pulpicie za pomoc narzdzi wyszczeglnionych na pasku narzdziowym okna zasobw. Na ekranie Sterowniki apletu pokazano przykadowe rozmieszczenie sterownikw Label, TextField i Panel. Ekran Sterowniki apletu
### controls.gif

Okrelanie waciwoci
Po naniesieniu sterownikw i pojemnikw na pulpit, naley okreli ich waciwoci: nazwy i opisy (Member, Caption), wygld (Look) i reakcje (Events). Na ekranach Nazwa przycisku, Wygld przycisku i Reakcja przycisku pokazano sposb okrelenia waciwoci dla przycisku opatrzonego napisem Exit. Ekran Nazwa przycisku
### member.gif

Ekran Wygld przycisku


### look.gif

23

Ekran Reakcja przycisku


### events.gif

Po wybraniu zdarzenia dotyczcego sterownika (np. clicked) i naciniciu przycisku Edit, zostanie wywietlone okno Class Editor, pokazane na ekranie Zdefiniowanie obsugi. W oknie tym mona okreli sposb reagowania sterownika na zdarzenie. Ekran Zdefiniowanie obsugi
### handler.gif

Komponowanie programu
Po wykonaniu podanych czynnoci dla wszystkich komponentw pulpitu, a nastpnie zamkniciu okna do projektowania zasobw, otrzymuje si gotowy program, ktry moe by poddany dodatkowej rcznej obrbce (m.in. skopiowaniu komentarza zawierajcego opis apletu do pliku z rozszerzeniem .html). Wygenerowany wizualnie program naley oczywicie zbudowa, uruchomi i wytestowa. Czynnoci te wykonuje si w identyczny sposb jak dla programu utworzonego rcznie.

24

Cz III

Podstawy programowania

Program rdowy jest zestawem napisw umieszczonych w moduach rdowych. Kady modu rdowy jest umieszczony w pliku. Modu rdowy skada si z komentarzy, deklaracji pakietu, deklaracji importu i definicji klas. Jeli modu rdowy zawiera definicj wicej ni jednej klasy, to tylko jedna z nich moe by publiczna. Klasa publiczna o nazwie Class musi by umieszczona w pliku o nazwie Class.java. Po skompilowaniu moduu rdowego powstaje modu wynikowy z rozszerzeniem .class. Z takich wanie moduw, po uzupenieniu ich moduami bibliotecznymi pochodzcymi z pliku classes.zip tworzy si program wynikowy.

_________________________________________________________________________________________

Leksemy
Modu rdowy skada si z odstpw i komentarzy oraz z sekwencji leksemw: sw kluczowych, identyfikatorw, operatorw i ogranicznikw.

Sowa kluczowe
Sowo kluczowe jest napisem sucym do zapisywania instrukcji programu. Do najczciej uywanych sw kluczowych nale
int if double else while for

Na przykad
int age; // ... if(age >= 18) youCanVote(); else youMustWait(); // wiek // // // // jeli skoczye 18 lat moesz gosowa w przeciwnym razie musisz zaczeka

Deklaracja zmiennej age zawiera sowo kluczowe int. Instrukcja warunkowa zawiera sowa kluczowe if i else.

Literay
Literaem jest nazwa zmiennej, ktrej warto i typ wynikaj z zapisu literau. Literaami s liczby cakowite (np. 12), liczby rzeczywiste (np. 1.2e+2), znaki (np. ('a') i acuchy (np. "Yes").

Liczby cakowite
Liczba cakowita dziesitna skada si z cigu cyfr dziesitnych. Liczba cakowita szesnastkowa skada si z napisu 0x po ktrym nastpuje cig cyfr szesnastkowych. Wartoci liczb typu "int" nale do przedziau
0 .. +9,223,372,036,854,775,807

Na przykad 12 0xc -12 liczba cakowita dziesitna liczba cakowita szesnastkowa wyraenie cakowite (warto: 12) (warto: 12)

25

Liczby rzeczywiste
Liczba rzeczywista skada si z dwch cigw cyfr dziesitnych oddzielonych kropk, po ktrych moe wystpi litera e z wykadnikiem. Cig cyfr przed albo po kropce moe by pominity. Kropk mona pomin tylko wwczas, gdy liczb zapisano z wykadnikie m albo gdy po liczbie wystpuje litera f. Wykadnik ma posta liczby cakowitej, ewentualnie poprzedzonej znakiem + ( plus) albo (minus). Wartoci liczb typu "double" nale do przedziau
0 .. 1.8e308

Na przykad 1.2 3e-2 -1.2 liczba rzeczywista liczba rzeczywista wyraenie rzeczywiste (warto: 1.2) (warto: 0.03)

Znaki
Litera znakowy ma posta 'c' w ktrej c jest znakiem widocznym (np. 'a'), symbolem znaku (np. '\n'), albo szesnastkowym kodem znaku (np. '\u0061'). Wartoci literau znakowego jest kod opisanego przeze znaku (np. wartoci literau 'a' jest 97). W tabeli Symbole znakw wymieniono kilka waniejszych literaw znakowych. Tabela Symbole znakw
###

Znak '\n' '\r' '\0' '\t' '\\' '\'' '\"'


###

Interpretacja znak nowego wiersza znak powrotu karetki znak o kodzie 0 znak tabulacji znak \ znak ' (krcej: ''') znak " (krcej: '"')

acuchy
acuchem jest napis "cc ... c", w ktrym kade c jest takim samym napisem jak w literale znakowym. Litera acuchowy skadajcy si z N znakw jest nazw odnonika do wektora o N+1 elementach typu "char", zainicjowanych kodami kolejnych znakw acucha oraz dodatkowo kodem znaku '\0' (liczb 0). Na przykad "Yes" "" nazwa odnonika do wektora zainicjowanego kodami znakw Y, e, s oraz kodem znaku '\0' (liczb 0) nazwa odnonika do 1-elementowego wektora zainicjowanego kodem znaku '\0'

Identyfikatory
Identyfikator jest napisem reprezentujcym element programu: pakiet, klas, procedur albo zmienn. Identyfikatory mog skada si tylko z liter i cyfr (dolar i podkrelenie s uznawane za litery), ale nie mog zaczyna si od cyfry. Liczba znakw identyfikatora nie jest ograniczona. Identyfikator nie moe skada si z takich samych znakw jak sowo kluczowe. Identyfikatorami s m.in. napisy
forSale ForSale forsale For_Sale $forSale

26

Nie jest identyfikatorem napis


4sale

Operatory
Operatorami s cigi znakw, suce do zapisywania operacji. Do najczciej uywanych operacji nale m.in.:

operacje arytmetyczne
+ * ++ += *= (dodawanie), (mnoenie), (zwikszenie o 1) (dodanie) (pomnoenie) / --= /= (odejmowanie), (dzielenie), (zmniejszenie o 1) (odjcie) (podzielenie)

porwnania
== < <= (rwne) (mniejsze) (mniejsze lub rwne) != > >= (nie rwne), (wiksze), (wiksze lub rwne)

operacje logiczne
! (negacja) && (koniunkcja) Na przykad
int num = 5, var = 7; var += -num++ / 2; System.out.println(var); System.out.println(num);

||

(dysjunkcja)

// 5 // 6

Instrukcja
var += -num++ / 2;

zawiera operatory
++ / +=

Wartoci kolejnych podwyrae s nastpujce


num num++ -num++ -num++ / 2 5 5 -5 -2

A zatem do zmiennej var dodaje si -2, czyli nadaje si jej warto 5.

Ograniczniki
Ogranicznikami s pojedyncze znaki oddzielajce albo koczce elementy programu. Najczciej uywanymi ogranicznikami s przecinki i redniki. Na przykad
for(int suma = 0, i = 0; i < 100 ; i++) suma = suma + i;

Przytoczona instrukcja zawiera 6 ogranicznikw (dwa nawiasy, przecinek i trzy redniki). 27

_________________________________________________________________________________________

Zmienne
Zmienna jest elementem programu wynikowego. W programie rdowym wystpuje pod postaci identyfikatora (np. var), literau (np. 12, 3.4, 'a', "Hello"), albo wyraenia (np. a+1). Zmienne mog by modyfikowalne albo niemodyfikowalne. Zmiennym modyfikowalnym mona, niemodyfikowalnym nie mona przypisywa danych. Zmienne niemodyfikowalne mog by nazywane staymi. a zmiennym

Uwaga: Zapis literau uznaje si za niejawn deklaracj reprezentowanej przeze zmiennej. Wszystkie pozostae zmienne musz by zadeklarowane jawnie, albo musz powsta jako rezultat wykonania operacji na zmiennych. W szczeglnoci kade wyraenie jest chwilow nazw pewnej zmiennej. Na przykad
int var; // ... var = var + 2;

Identyfikator var jest nazw zmiennej typu "int". Wyraenie


var + 2

jest chwilow nazw rezultatu operacji dodawania. Wyraenie


var = var + 2

jest chwilow nazw rezultatu operacji przypisania.

Identyfikowanie zmiennych
Do identyfikowania zmiennych su ich nazwy. Nazw zmiennej modyfikowalnej jest identyfikator, a nazw zmiennej niemodyfikowalnej litera. Wyraenie jest nazw zmiennej modyfikowalnej tylko wwczas, gdy jest l-nazw. O tym, czy rezultat operacji jest czy nie jest l-nazw decyduje opis operacji. Decyzje takie zostay podjte arbitralnie przez twrcw jzyka. W szczeglnoci jest l-nazw kady identyfikator zmiennej (z wyjtkiem odnonika this), ale nie jest ni wyraenie arytmetyczne (np. 2 + 3), ani nazwa rezultatu przypisania (np. a = 12) Uwaga: Okrelenie l-nazwa bierze si std, e tylko taka nazwa zmiennej moe wystpi jako lewy argument operacji przypisania. Na przykad
int var = 12; ++++var; (var = 2) = 3; this = null // bd (++var nie jest l-nazw) // bd (var = 2 nie jest l-nazw) // bd (this nie jest l-nazw)

Modyfikowanie zmiennych
Modyfikowanie zmiennych odbywa si za pomoc operacji przypisania oraz za pomoc operacji wejcia. Na przykad
int chr, fix; fix = 'a'; // ... chr = System.in.read();

Zmienna fix jest modyfikowana za pomoc operacji przypisania, a zmienna chr jest modyfikowana za pomoc operacji wejcia. 28

Przeksztacanie zmiennych
Do przeksztacenia zmiennej w inn zmienn suy konwersja. Konwersja, ktra moe by zastosowana niejawnie jest konwersj standardow. Konwersja standardowa jest konwersj dopuszczaln (poprawn skadniowo), ale nie musi by konwersj wykonaln (poprawn semantycznie). Wyraenie poddane konwersji zapisuje si w postaci
(Type)exp

w ktrej Type jest nazw typu docelowego (najczciej identyfikatorem typu), a exp jest wyraeniem, ktre mona podda konwersji do typu "Type". Uwaga: Nazwa zmiennej, ktra jest rezultatem konwersji nie jest l-nazw. Na przykad
int num = (int)12.0; double dbl = 12; int fix = 12.0; (int)fix = 12; // // // // dobrze (jawna konwersja) dobrze (niejawna konwersja) bd (brak jawnej konwersji) bd ((int)Fix nie jest l-nazw)

Promocje
Przed wykonaniem pewnych operacji jednoargumentowych jest wykonywana promocja do typu oglniejszego (np. z typu " char" do typu "int"). Takie przeksztacenie jest wykonywane niejawnie. Na przykad
char chr = 'a'; System.out.print(chr); System.out.print((int)chr); System.out.print(+chr); // a // 97 // 97

Przed wykonaniem operacji +chr dokonano promocji z typu "char" do typu "int".

Typ wsplny
Przed wykonaniem pewnych operacji dwuargumentowych jest wykonywane przeksztacenie argumentw do najwszego typu oglniejszego, stanowicego wwczas typ wsplny argumentw. Przeksztacenie takie jest wykonywane niejawnie. Na przykad
char chr = 'a'; System.out.print((int)chr & 0x21); System.out.print(chr & 0x21); // // // 0000 0000 0110 0001 33 33

Przed wykonaniem operacji chr & 0x21 przeksztacono argument chr do typu wsplnego "int".

_________________________________________________________________________________________

Zmienne orzecznikowe
Zmiennymi orzecznikowymi (krtko: orzecznikami) s zmienne typu "boolean". Zmiennym orzecznikowym mona przypisywa orzeczenia reprezentujce prawd (true) albo fasz (false). Na orzecznikach mona wykonywa operacje negacji (!), koniunkcji (&&) i dysjunkcji (||). Operacja negacji jest jednoargumentowa, a operacje koniunkcji i dysjunkcji s dwuargumentowe.

29

Negacja
Jeli var jest orzecznikiem o wartoci false, to rezultatem operacji !var jest orzecznik o wartoci true. Jeli var jest orzecznikiem o wartoci true, to rezultatem operacji !var jest orzecznik o wartoci false. Na przykad
boolean var = false; var = !var;

Po opracowaniu deklaracji, orzecznik var ma warto false. Po opracowaniu przypisania, orzecznik var ma warto true.

Koniunkcja
Koniunkcja dwch argumentw ma warto true tylko wwczas, gdy kady z nich ma warto true. Jeli lewy argument ma warto false, to rezygnuje si z opracowania prawego. Na przykad
boolean one = true, two = false; boolean var; var = one && two; two = var && fun();

Zmiennej var przypisano warto false. Podczas wykonywania ostatniej instrukcji nie dojdzie do wykonania funkcji fun.

Dysjunkcja
Dysjunkcja dwch argumentw ma warto false tylko wwczas, gdy kady z nich ma warto false. Jeli lewy argument ma warto true, to rezygnuje si z opracowania prawego. Na przykad
boolean one = true, two = false; boolean var; var = one || fun();

Zmiennej var przypisano warto true. Podczas wykonywania ostatniej instrukcji nie dojdzie do wykonania funkcji fun.

_________________________________________________________________________________________

Zmienne arytmetyczne
Zmiennymi arytmetycznymi s zmienne cakowite (np. typu "int") i rzeczywiste (np. typu "double"). Na zmiennych arytmetycznych mona wykonywa podstawowe dziaania arytmetyczne: dodawanie, odejmowanie, mnoenie i dzielenie, operacje zwikszenia i zmniejszenia wartoci o 1 oraz operacje porwania.

Zmienne cakowite
Najczciej uywanymi zmiennymi cakowitymi s 4 -bajtowe zmienne typu "int". Mona w nich przechowywa dane liczbowe z przedziau 30

-2,147,483,648 .. 2,147,483,647 Rzadziej s uywane zmienne cakowite typu "byte", "short" i "long". Zakresy ich wartoci przytoczono w tabeli Pozostae zmienne cakowite. Uwaga: Nie ma literaw typu "byte" i "short". Litera typu "long" ma posta literau typu "int" zakoczonego liter L albo l (np. 12L). Tabela Pozostae zmienne cakowite
###

Typ byte short long


###

Rozmiar 1-bajt 2-bajty 8-bajtw

Wartoci (od (od (od -128 do 127) -32768 do 32767) -9,223,372,036,854,775,808 do +9,223,372,036,854,775,807)

Zmienne rzeczywiste
Najczciej uywanymi zmiennymi rzeczywistymi s 8-bajtowe zmienne typu "double". Mona w nich przechowywa dane liczbowe z przedziau -1.8e308 .. 1.8e308 Rzadziej s uywane 4-bajtowe zmienne typu "float". Mona w nich przechowywa dane liczbowe z przedziau -3.4e38 .. 3.4e38 Uwaga: Litera typu "float" ma posta literau typu "int" albo "double" zakoczonego liter F albo f (np. 12f).

Podstawowe dziaania arytmetyczne


Rezultatem podstawowego dziaania arytmetycznego jest zmienna arytmetyczna o wartoci okrelonej przez to dziaanie. Jeli operacja jest dwuargumentowa, a jeden z argumentw jest typu " double", to i rezultat operacji jest typu " double". Na przykad
int fix = 12; double dbl = 3.4; double var; var = fix + dbl;

Zmiennej var przypisano dan typu "double" o wartoci 15.4. Uwaga: Jeli zmienna arytmetyczna jest poczona operatorem + (plus) ze zmienn acuchow, to zmienna arytmetyczna jest przeksztacana w acuchow, a nastpnie tworzy si zmienn acuchow skadajc si z wszystkich znakw obu acuchw. W szczeglnoci, rezultatem operacji
"" + 12

jest "12", rezultatem operacji


"" + 2 + 3

jest "23", a rezultatem operacji


"Wynik: " + (2 + 3)

jest
"Wynik: 5"

31

Operacje zwikszenia i zmniejszenia


Rezultatem nastpnikowej operacji zwikszenia (++) jest zmienna o takiej wartoci jak ma argument operacji. Skutkiem ubocznym operacji zwikszenia jest dodanie do argumentu liczby 1. Rezultatem nastpnikowej operacji zmniejszenia (--) jest zmienna o takiej wartoci jak ma argument operacji. Skutkiem ubocznym operacji zmniejszenia jest odjcie od argumentu liczby 1. Na przykad
int fix = 12; int num = fix++; fix = num--;

Tu przed wykonaniem ostatniej instrukcji zmienna fix oraz zmienna num ma warto 12. Tu po wykonaniu ostatniej instrukcji zmienna fix ma wartoc 12, a zmienna num ma warto 11.

Operacje porwnania
Rezultatem operacji porwnania: == (rwne), != (nie rwne), < (mniejsze), > (wiksze), <= (mniejsze lub rwne), >= (wiksze lub rwne) jest orzecznik o wartoci okrelajcej prawdziwo porwnania (np. 12 > 10 ma warto true). Uwaga: Specjalnej ostronoci wymaga uycie operatora rwne. Jeli zapomni si o tym, e skada si z pary znakw rwnoci, to faktycznie stanie si operatorem przypisania. Na przykad
int fix; // ... if(fix >= 100 && fix <= 200) System.out.println("Warto zmiennej fix " + "naley do przedziau 100 .. 200"); if(fix == 100) System.out.println("Zmienna fix ma warto 100");

Wykonanie instrukcji warunkowych powoduje wyprowadzenie napisu dotyczcego aktualnej wartoci zmiennej fix. Gdyby w ostatniej instrukcji relacj
fix == 100

omykowo zastpiono operacj przypisania


fix = 100

to niezalenie od wartoci zmiennej fix wyprowadzono by napis


Zmienna fix ma warto 100

_________________________________________________________________________________________

Zmienne znakowe
Zmienne znakowe s 16-bitowymi zmiennymi arytmetycznymi. Mog by uywane w taki sam sposb jak pozostae zmienne arytmetyczne, ale ich gwnym przeznaczeniem jest reprezentowanie kodw znakw, zarwno znakw europejskich jak i znakw uywanych w krajach azjatyckich. Dane znakowe s znakami Unikodu. Jego pierwszych 256 znakw jest identycznych ze znakami kodu ASCII Latin-1. Wartoci wszystkich znakw Unikodu s nieujemne. Na przykad
char chr;

32

// ... if(chr >= 'a' && chr <= 'z') System.out.println("Kod przypisany zmiennej chr " + "jest kodem litery a .. z"); if(chr == 'm') System.out.println("Kod przypisany zmiennej chr " + "jest kodem litery m");

Wykonanie instrukcji warunkowych powoduje wyprowadzenie napisu dotyczcego aktualnej warto ci zmiennej chr.

___________________________________________________________________________ ______________

Zmienne odnonikowe
Zmienne odnonikowe su do identyfikowania zmiennych obiektowych, m.in. zmiennych predefiniowanego typu acuchowego "String". Identyfikowanie odbywa si za pomoc odniesie przypisywanych odnonikom. Kada taka dana zawiera informacj o adresie i typie identyfikowanego przez ni obiektu Uwaga: Odnonikowi dowolnego typu mona przypisa odniesienie puste reprezentowane przez sowo kluczowe null. Po wykonaniu takiego przypisania odnonik nie identyfikuje adnego obiektu.

Identyfikowanie zmiennych
Zmienna odnonikowa typu "Class" moe identyfikowa zmienne klasy Class oraz zmienne dowolnej jej podklasy. W szczeglnoci, poniewa klasa Applet jest podklas klasy Panel, wic odnonik ref zadeklarowany za pomoc instrukcji
Panel ref;

moe identyfikowa zarwno zmienne klasy Panel jak i zmienne klasy Applet. Na odnonikach nie wolno wykonywa innych operacji ni porwnanie odnonikw i przypisanie odniesienia. Jeli dwa odnoniki identyfikuj t sam zmienn, to rezultat operacji == (rwne) ma warto true, a rezultat operacji != (nie rwne) ma warto false. Na przykad
String h = "Hello"; String w = "World"; System.out.println(h + " " + w);

Odnonik h identyfikuje obiekt zainicjowany acuchem Hello, a odnonik w identyfikuje obiekt zainicjowany acuchem World. Rezultatem operacji
h + " " + w

jest odnonik identyfikujcy obiekt zainicjowany acuchem


Hello World

_________________________________________________________________________________________

Zmienne acuchowe
Zmienn acuchow jest zmienna obiektowa predefiniowanego typu " String" albo "StringBuffer". Podobnie jak obiekty innych typw, zmienne acuchowe s identyfikowane przez odnoniki. Poniewa porwnanie odnonikw polega jedynie na sprawdzeniu, czy identyfikuj one te same obiekty, porwnanie wartoci zmiennych acuchowych moe by wykonane tylko za pomoc specjalnych metod, takich jak equals i compareTo. Uwaga: Zasada porwnywania acuchw jest nastpujca: 1) jeli acuchy skadaj si z takich samych znakw, to uznaje si je za rwne, 2) w przeciwnym ignoruje si pocztkowe znaki acuchw (jeli s parami identyczne), a porwnanie acuchw zastpuje porwnaniem pierwszej pary znakw nieidentycznych (znak o mniejszym kodzie uznaje si za mniejszy). 33

public boolean equals(Object obj)

Rezultatem metody equals uytej w wyraeniu


str1.equals(str2)

jest orzecznik o wartoci true jeli odnoniki str1 i str2 identyfikuj zmienne acuchowe zainicjowane takimi samymi acuchami. W przeciwnym razie orzecznik ma warto false. Na przykad
String str = "$"; String one = str + "100"; String two = str + "100"; System.out.println(one == two); System.out.println(one.equals(two));

// false // true

public int compareTo(String str)

Rezultatem metody compareTo uytej w wyraeniu


str1.compareTo(str2)

jest zmienna typu "int" o wartoci ujemnej, zero, albo dodatniej, odpowiednio do tego czy odnoniki str1 i str2 identyfikuj zmienne zainicjowane takimi acuchami, e pierwszy jest mniejszy od drugiego, oba s rwne, albo pierwszy jest wikszy od drugiego. Na przykad
String one; String two; // ... int res = one.compareTo(two); if(res < 0) System.out.println("Pierwszy acuch jest mniejszy"); if(res == 0) System.out.println("acuchy s rwne"); if(res > 0) System.out.println("Pierwszy acuch jest wikszy");

Jeli tu przed uyciem metody compareTo wykonano instrukcje


one = "ABC"; two = "Ab";

to poniewa kod litery b (98) jest wikszy od kodu litery B (42), wic nastpi wyprowadzenie napisu
Pierwszy acuch jest mniejszy

_________________________________________________________________________________________

Instrukcje
Instrukcja jest opisem czynnoci. Kada instrukcja moe by poprzedzona etykiet (albo wicej ni jedn etykiet). Etykieta ma posta identyfikatora, a od instrukcji (albo od etykiety) oddziela j znak : (dwukropek). Na przykad
void sub(int par) { Lab: while(true) if(par++ < 0) break Lab; }

// etykieta // odwoanie do etykiety

34

Instrukcja deklaracyjna
Instrukcja deklaracyjna ma posta
spec dcl, dcl, ... , dcl;

w ktrej spec jest zestawem specyfikatorw, a kade dcl jest deklaratorem zmiennej albo deklaratorem z inicjatorem.

Specyfikatory
Specyfikatory su do okrelenia typu zmiennych i rezultatw procedur, a ponadto okrelaj dodatkowe atrybuty zmiennych, procedur i klas, takie jak dostpno statyczno rodzimo ustalono synchroniczno ulotno nietrwao Na przykad
public final class Master { public static final double Pi = 3.14; // ... }

private, protected, public static native final synchronized volatile transient

Klasa Master jest publiczna (dostpna z wszystkich klas) i ustalona (nie moe by podklas innej klasy). Zmienna Pi jest publiczna (dostpna z wszystkich klas), statyczna (istnieje od chwili zaadowania do chwili wyadowania klasy) i ustalona (nie moe by modyfikowana).

Deklaratory
Deklarator suy do okrelenia nazwy zmiennej. Jeli zmienna jest odnonikiem do tablicy, to deklarator zawiera informacj o liczbie jej wymiarw. Uwaga: Sposb rozmieszczenia par nawiasw kwadratowych okrelajcych liczb wymiarw tablicy jest dowolny. W obrbie nawiasw kwadratowych nie moe wystpi aden napis. Na przykad
int var; int vec[]; String[] arr[]; int mtx[2][]

// String arr[][]; String [][]arr; // bd (liczba w obrbie nawiasw)

Deklaratorami s var, vec[] i []arr[]. Identyfikator vec jest nazw zmiennej typu "int", a identyfikatory vec i arr s nazwami odnonikw do tablic zmiennych, odpowiednio 1-wymiarowej i 2-wymiarowej (wynika to z liczby par nawiasw kwadratowych).

Inicjatory
Inicjator deklaratora moe mie jedn z nastpujcych postaci
= exp = { phi, phi, ... , phi } inicjator wyraeniowy inicjator klamrowy

w ktrych exp jest wyraeniem a kade phi jest wyraeniem, albo fraz inicjujc o postaci
{ phi, phi, ... , phi }

Opracowanie instrukcji deklaracyjnej powoduje zadeklarowanie wymienionych w niej zmiennych oraz ewentualne zainicjowanie ich wartociami wyrae wymienionych w inicjatorach. 35

Uwaga: Inicjator klamrowy moe by uyty tylko do inicjowania tablic. Przykad Instrukcje deklaracyjne
int varA; int varB = 10; int var1, var2 = 20, var3; int lotto[] = { 12, 45, 6, String monolog[] = { "To", int matrix[][] = { { 10, { 20, { 30, }; int var5(50); int varC = { 10 };

32, 18, 5 }; "be", "or", "not", "to", "be" }; 20, 30, 40 }, 30, 40, 50 }, 40, 50, 60 } // bd (niewaciwy inicjator) // bd (niewaciwy inicjator)

Zmienna matrix jest odnonikiem do 2-wymiarowej tablicy o 2 wierszach i 4 kolumnach.

Zakres deklaracji
W punkcie bezporednio za deklaratorem zaczyna si zakres deklaracji zmiennej. Koczy si on w miejscu zakoczenia najwszego bloku, w ktrym wystpia ta deklaracja. Uwaga: Blokiem jest fragment programu zawarty midzy par odpowiadajcych sobie nawiasw klamrowych. Na przykad
import java.io.IOException; public class Master { public static void main(String args[]) throws IOException { if(args.length > 0) { String allArgs = ""; for(int i = 0; i < args.length ; i++) { System.out.println( "Argument #" + i + ": " + args[i] ); allArgs += args[i] + ' '; } System.out.println("All arguments: " + allArgs); } else System.out.println("Program was called " + "with no arguments!"); System.in.read(); } }

W programie wystpuj 4 wzajemnie zawierajce si bloki. Wykonanie programu powoduje wyszczeglnienie jego argumentw, na przykad
Argument #0: Ewa Argument #1: Jan All arguments: Ewa Jan

albo wyprowadzenie napisu


Program was called with no arguments!

Kolidowanie deklaracji
W zakresie deklaracji zmiennej nie moe wystpi deklaracja zmiennej oznaczonej takim samym identyfikatorem. 36

Przykad Kolidowanie deklaracji


void sub(int age) { System.out.println(age); { int age = 12; // bd (kolizja z parametrem) // ... { int age = 20; // bd (dodatkowa kolizja) String name = "Bob"; // ... } String name = "Tom"; // ... for(int i = 0; i < 10 ; i++) // ... for(int i = 10; i > 0 ; i--) // ... } }

Odnonik name identyfikujcy obiekt zainicjowany acuchem "Bob" nie koliduje z odnonikiem name identyfikujcym obiekt zainicjowany acuchem "Tom". Nie wystpuje kolizja midzy identyfikatorami i wystpujcymi w instrukcjach for.

Instrukcja pusta
Instrukcja pusta ma posta
;

Jej wykonanie nie wywouje adnych skutkw. Przykad Instrukcja pusta


void fun() { int i = 10000; JustLabel: ; while(i-- != 0) ; Fin: }

// instrukcja pusta // instrukcja pusta // bd (brak instrukcji pustej)

Instrukcja grupujca
Instrukcja grupujca ma posta
{ Ins Ins ... Ins }

w ktrej kade Ins jest dowoln instrukcj. Wykonanie instrukcji grupujcej skada si z sekwencyjnego wykonania zawartych w niej instrukcji Ins. Uwaga: Uycie instrukcji grupujcej ma na celu utworzenie z sekwencji instrukcji dokadnie jednej instrukcji. Przykad Instrukcje grupujce
int i = -100; do { System.out.print(i++); i++; } while(i < 0);

37

do System.out.print(i++); i++; // bd (brak instrukcji grupujcej) while(i < 100);

Midzy pierwsz par sw kluczowych do i while wystpuje instrukcja grupujca.

Instrukcja wyraeniowa
Instrukcja wyraeniowa ma posta exp; w ktrej exp jest wyraeniem. Wykonanie instrukcji wyraeniowej skada si z opracowania wyraenia exp, a nastpnie zignorowania rezultatu tego opracowania. Uwaga: Wykonanie instrukcji wyraeniowej powinno pociga za sob skutki uboczne, takie jak przypisywanie i przesyanie danych. W przeciwnym razie uycie jej jest zbyteczne. Przykady Instrukcje wyraeniowe
int var; // ... var = 10; var1 = var2 = 10; var = System.in.read(); System.in.read(); System.out.println(var);

// // // // //

przypisanie przypisanie przesanie przesanie przesanie

Instrukcja warunkowa
Instrukcja warunkowa ma posta
if(exp) InsT

albo
if(exp) InsT else InsF

w ktrych exp jest wyraeniem orzecznikowym, a InsT oraz InsF jest instrukcj. Jeli InsT jest instrukcj warunkow, to obowizuje zasada, e kadej frazie else odpowiada najblisza z lewej, poprzedzajca j fraza if. W szczeglnoci, instrukcja
if(exp1) if(exp2) Ins1 else Ins2

jest rwnowana instrukcji


if(exp1) { if(exp2) Ins1 else Ins2 }

a nie instrukcji
if(exp1) { if(exp2) Ins1 } else Ins2

Wykonanie instrukcji warunkowej zaczyna si od wyznaczenia wartoci wyraenia exp. Jeli wyraenie ma warto true, to jest wykonywana instrukcja InsT, a w przeciwnym razie instrukcja InsF (o ile wystpuje). Po wykonaniu tych czynnoci wykonanie instrukcji warunkowej uznaje si za zakoczone. Przykad Instrukcje warunkowe
if(var < 5 && var != 0) System.out.println(var);

38

if(flag || var >= 5) var = 0; else System.out.println(var); if(var >= 0) { if(var <= 9) System.out.println(var); } else var = -1;

Instrukcja grupujca zostaa uyta po to, aby przed fraz else nie wystpia instrukcja grupujca bez frazy else. Gdyby pominito nawiasy klamrowe, to rozpatrywana instrukcja przybraaby posta
if(var >= 0) if(var <= 9) System.out.println(var); else var = -1;

rwnowan
if(var >= 0) { if(var <= 9) System.out.println(var); else var = -1; }

a zatem o istotnie rnej semantyce.

Instrukcje ptli
Instrukcje ptli umoliwiaj cykliczne wykonywanie objtych nimi instrukcji. Instrukcja ptli powinna by skonstruowan a w taki sposb, aby istniaa gwarancja zakoczenia jej wykonywania.

Instrukcja while
Instrukcja while ma posta
while(exp) Ins

w ktrej exp jest wyraeniem orzecznikowym, a Ins jest instrukcj. Wykonanie instrukcji while skada si z cyklicznego wykonywania nastpujcych czynnoci 1. 2. Opracowania i wyznaczenia wartoci wyraenia exp. Jeli wyraenie expC ma warto true, wykonania instrukcji Ins.

Jeli wyraenie ma warto false, to wykonanie instrukcji while uznaje si za zakoczone. Uwaga: Jeli pierwsz wartoci exp jest false, to instrukcja Ins w ogle nie bdzie wykonana. Przykad Instrukcja while
int val = 3; while(val-- != 0) System.out.println(val);

// 2 1 0

Opracowanie wyraenia
val-- != 0

ma skutek uboczny w postaci zmniejszenia wartoci zmiennej val. 39

Dziki temu, po wykonaniu trzech obrotw ptli, nastpi zakoczenie wykonywania instrukcji while.

Instrukcja for
Instrukcja for ma posta
for(Ins0 expC ; expI) Ins

w ktrej Ins0 jest instrukcj wyraeniow albo deklaracyjn, expC jest wyraeniem orzecznikowym, expI jest wyraeniem, a Ins jest instrukcj. Wykonanie instrukcji for skada si z jednokrotnego wykonania instrukcji Ins0, a nastpnie z cyklicznego wykonywania nastpujcych czynnoci 1. 2. Opracowania i wyznaczenia wartoci wyraenia expC. Jeli wyraenie expC ma warto true, wykonania instrukcji Ins oraz instrukcji wyraeniowej utworzonej z wyraenia expI.

Jeli wyraenie expC ma warto false, to wykonanie instrukcji for uznaje si za zakoczone. Uwaga: Warto odnotowa, e wykonanie instrukcji
for(Ins0 expC ; expI) Ins

ma na og taki sam skutek jak wykonanie instrukcji


Ins0 while(expC) { Ins expI; }

Przykad Instrukcja for


for(int var = 0; var < 3 ; var++) System.out.println(var); // 0 1 2 int var; for(var = 3; var > 0 ; var--) System.out.println(var); // 3 2 1

Instrukcja do
Instrukcja do ma posta
do Ins while(exp);

w ktrej Ins jest instrukcj, a exp jest wyraeniem orzecznikowym. Wykonanie instrukcji do skada si z cyklicznego wykonywania nastpujcych czynnoci 1. 2. 3. Wykonania instrukcji Ins. Opracowania i wyznaczenia wartoci wyraenia exp. Jeli wyraenie exp ma warto true, ponownego wykonania podanych czynnoci.

Jeli wyraenie exp ma warto false, to wykonanie instrukcji do uznaje si za zakoczone. Uwaga: Instrukcja Ins jest wykonywana co najmniej jeden raz. Przykad Instrukcja do
int val = 3; do

40

System.out.println(val); while(val-- != 0);

// 3 2 1 0

Poniewa badanie warunku odbywa si dopiero po wykonaniu instrukcji zawartej midzy do i while, wic liczba "obrotw" ptli d o jest o 1 wiksza ni liczba obrotw podobnej do niej instrukcji while.

Instrukcje zaniechania i kontynuowania


We wntrzu ptli mog by uyte instrukcje
break;

oraz
continue;

Wykonanie instrukcji zaniechania (break) powoduje zakoczenie wykonywania ptli, natomiast wykonanie instrukcji kontynuowania (continue) powoduje wykonanie takich czynnoci, jakby zakoczyo si wykonywanie wszystkich instrukcji objtej ptl (co spowoduje kontynuowanie wykonywania ptli). Przykad Instrukcje break i continue
int sum = 0; for(int i = 1; i <= 9 ; i++) { if(i < 3) { sum--; continue; } else if(sum > 7) break; sum = sum + 2*i; } System.out.println("Sum = " + sum);

Zmienna sum przyjmuje kolejno wartoci: -1, -2, 4, 12. Zakoczenie wykonywania ptli for nastpuje znacznie wczeniej ni wynikaoby z rozpatrzenia jej pierwszego wiersza. Wykonanie podanego wycinka programu powoduje wyprowadzenie napisu
Sum = 12

Uycie etykiet
Instrukcje zaniechania i kontynuowania mog mie rwnie posta
break Lab;

oraz
continue Lab;

w ktrych Lab jest etykiet. W takim wypadku wykonanie instrukcji zaniechania powoduje zakoczenie wykonywania ptli poprzedzonej podan etykiet, a wykonanie instrukcji kontynuowania powoduje kontynuowanie wykonania ptli poprzedzonej podan etykiet. Przykad Instrukcja zaniechania z etykiet
int arr[][] = { { 1, 2, 3 }, { 4, 0, 5 }, { 1, 1, 0 } }; int sum = 0; Loop: for(int i = 0; i < 3 ; i++) for(int j = 0; j < 3 ; j++) if(arr[i][j] == 0) break Loop; else

41

sum += arr[i][j]; System.out.println(sum);

Ptla sumuje kolejne wiersze tablicy, ale koczy si w chwili napotkania elementu o wartoci 0. Wykonanie programu powoduje wyprowadzenie liczby 10. Gdyby z instrukcji zaniechania usunito etykiet, nastpioby wyprowadzenie liczby 12.

Instrukcja wyboru
Instrukcja wyboru ma na og posta
switch(exp0) { Case Case ... Case Default }

w ktrej kade Case jest fraz o postaci


case exp: Ins Ins ... break;

a Default jest fraz o postaci


default: Ins Ins ... Ins

W takim zapisie, exp0 jest wyraeniem cakowitym, kade exp jest wyraeniem staym cakowitym (zazwyczaj literaem albo symbolem), a kade Ins jest instrukcj, albo jest napisem pustym. Na przykad
void sub(int par) throws IllegalArgumentException { switch(par) { case 0: System.out.print("0"); break; case -1: System.out.print("-1"); break; case +1: System.out.print("+1"); break; default: System.out.print("Wrong value"); throw new IllegalArgumentException(); } System.out.println(); }

Wykonanie instrukcji wyboru zaczyna si od opracowania i wyznaczenia wartoci wyraenia exp0. Nastpnie warto tego wyraenia jest porwnywana z wartociami wyrae exp zawartych w kolejnych frazach Case, a do stwierdzenia rwnoci. W takim wypadku s wykonywane instrukcje danej frazy. W przeciwnym razie s wykonywane instrukcje frazy Default (domniemana fraza Default skada si z jednej instrukcji break;). Po zakoczeniu tych czynnoci wykonanie instrukcji wyboru uznaje si za zakoczone. Uwaga: Jeli frazy Case nie koczy instrukcja break;, to bezporednio po wykonaniu jej instrukcji Ins s wykonywane instrukcje nastpnych fraz, a do napotkania instrukcji zaniechania ( break) bd powrotu (return), albo do koca instrukcji wyboru.

Instrukcje powrotu
Instrukcja powrotu ma posta
return;

albo 42

return exp;

w ktrej exp jest wyraeniem. Wykonanie instrukcji powrotu powoduje zakoczenie wykonywania zawierajcej j procedury. Jeli procedura jest rezultatowa (jest typu rnego od "void"), to jej rezultat jest inicjowany wartoci wyraenia exp (po ewentualnej konwersji do typu rezultatu). Przykad Instrukcja powrotu
static double fun(int par) { if(par > 0) return par * par; // return (double)(par * par); else return 0.0; }

Jeli funkcja fun zostanie wywoana w instrukcji


System.out.print(fun(2));

to wartoci jej rezultatu bdzie 4.0.

Instrukcja obsugi wyjtkw


Instrukcja do obsugi wyjtkw ma posta
try Block Catch Finally

w ktrej Block jest instrukcj grupujc, Catch jest niepustym zestawem fraz
catch(Dcl) Block

w ktrych Dcl jest deklaracj parametru anonimowej funkcji do obsugiwania wyjtkw, a Finally jest nieobowizkow fraz
finally Block

Na przykad
int len = 3, vec[]; try { vec = new int [len]; // ... } catch(OutOfMemoryError e) { // ... } catch(Exception e) { // ... } finally { vec = null; // ... }

Wykonanie instrukcji try skada si z wykonania instrukcji grupujcej wystpujcej bezporednio po fraz ie try. Jeli podczas jej wykonywania wystpi sytuacja wyjtkowa (spowodowana na przykad brakiem pamici na stercie), to wykonanie instrukcji grupujcej uzna si za zakoczone, a wysany wwczas wyjtek (obiekt klasy wyjtku) zostanie odebrany i obsuony przez t pierwsz fraz catch, ktrej parametr mona skojarzy z wysanym wyjtkiem. Niezalenie od tego jaki by przebieg wykonania instrukcji try, ale bezporednio przed jej zakoczeniem, jest wykonywany blok frazy finally. 43

Jeli adna z fraz catch instrukcji try nie jest w stanie odebra wyjtku, to jest on wysyany do najwszej dynamicznie, obejmujcej j, instrukcji try. Jeli takiej nie ma, to domylnie nastpuje zakoczenie wykonywania programu. Uwaga: Jeli wystpienie sytuacji wyjtkowej spowoduje zaniechanie dalszego wykonywania jakiegokolwiek bloku programu, to nastpi niejawne zniszczenie wszystkich jeszcze nie zniszczonych jego zmiennych lokalnych. Na przykad
import java.io.IOException; public class Master { public static void main(String args[]) throws IOException { String str = fun("Hello"); // ... System.in.read(); } static String fun(String str) { try { int fix = 12; // ... return getStr(str); } catch(OutOfMemoryError e) { System.out.println("Buy more RAM!"); System.exit(0); return null; // wymagane! } } static String getStr(String str) throws OutOfMemoryError { String strRef; try { strRef = new String(str); System.out.println(strRef.charAt(0)); } catch(NullPointerException e) { System.exit(1); return null; } return strRef; } }

Jeli podczas wykonywania instrukcji


strRef = new String(str);

zostaby wysany wyjtek klasy OutOfMemoryError, to poniewa nie mgby zosta odebrany przez fraz
catch(NullPointerException e)

wchodzc w skad instrukcji try funkcji getStr, wic zostaby wysany do dynamicznie obejmujcej j instrukcji try funkcji fun, gdzie zostaby przechwycony przez fraz
catch(OutOfMemoryError e)

Naley zwrci uwag, e tu po rozpatrzeniu fraz catch instrukcji try nalecej do funkcji getStr zostanie zniszczona zmienna strRef, a tu przed rozpatrzeniem fraz catch instrukcji try nalecej do funkcji fun zostanie zniszczona zmienna fix.

________________________________________________________________________________________

Tablice
Tablica jest wektorem elementw, z ktrych kady jest takiego samego typu. Elementami tablicy mog by tylko zmienne typu podstawowego oraz odnoniki do tablic i obiektw. 44

Z kadym elementem tablicy jest zwizany indeks, okrelajcy pozycj elementu w obrbie tablicy. Indeks pierwszego elementu ma warto 0. Przetwarzanie elementw tablicy odbywa si za porednictwem odnonika identyfikujcego tablic. Jeli nazw odnonika jest ref, to wyraenie
ref[exp]

w ktrym exp jest wyraeniem cakowitym, jest nazw elementu o indeksie rwnym wartoci wyraenia exp, za wyraenie
ref.length

jest nazw zmiennej o wartoci rwnej liczbie elementw tablicy.

Elementy podstawowe
Jeli Type jest nazw typu podstawowego (np. " int" albo "double"), to deklaracja
Type ref[]

oznajmia, e ref jest odnonikiem do wektora elementw typu podstawowego, z ktrych kady jest typu " Type". Podczas opracowania takiej deklaracji, odnonikowi ref jest przypisywane odniesienie puste. Odniesienie niepuste mona przypisa na dwa sposoby: albo za pomoc takiego inicjatora jak
= { 10, 20, 30 }

okrelajcego wartoci elementw, na przykad


int vec[] = { 10, 20, 30 };

albo za pomoc wyraenia fabrykujcego


new Type [size]

dostarczajcego odnonik do size-elementowego wektora, ktrego elementy maj wartoci 0, na przykad


new int [width * height]

A zatem, wykonanie nastpujcej instrukcji


int arr[] = { 10, 20, 30 };

moe by zastpione wykonaniem instrukcji


int arr[]; arr = new int [3]; for(int i = 0; i < arr.length ; i++) arr[i] = 10 * (i+1);

Przykad Sumowanie elementw


import java.io.IOException; public class Master { public static void main(String args[]) throws IOException { int vec[] = { 10, 20, 30 }; int sum = 0; for(int i = 0; i < vec.length ; i++) sum = sum + vec[i]; System.out.println("Sum = " + sum); System.in.read();

45

} }

Wykonanie programu powoduje wyprowadzenie napisu


Sum = 60

Elementy odnonikowe
Jeli Type jest nazw typu odnonikowego (np. " String" albo "StringBuffer"), to deklaracja
Type ref[]

oznajmia, e ref jest odnonikiem do wektora odnonikw, z ktrych kady jes t typu "Type". Podczas opracowania takiej deklaracji, odnonikowi ref jest przypisywane odniesienie puste. Odniesienie niepuste mona przypisa na dwa sposoby: albo za pomoc takiego inicjatora klamrowego jak
= { "Hello", "World" }

okrelajcego wartoci elementw, na przykad


String vec[] = { "Hello", "World" };

albo za pomoc wyraenia fabrykujcego


new Type [size]

dostarczajcego odnonik do size-elementowego wektora, ktrego elementy maj wartoci null, na przykad
new String [rows * cols]

A zatem, wykonanie nastpujcej instrukcji


String arr[] = { "Hello", "World" };

moe by zastpione wykonaniem instrukcji


String arr[]; arr = new String [2]; arr[0] = "Hello"; arr[1] = "World";

Przykad Wyznaczenie redniej argumentw


import java.io.IOException; public class Master { public static void main(String args[]) throws IOException, NumberFormatException { if(args.length == 0) System.out.println("Please supply arguments"); System.in.read(); return; } int sum = 0, count = args.length; for(int i = 0; i < count ; i++) { String arg = args[i]; int val = Integer.parseInt(arg); sum = sum + val; } System.out.println(sum / count); System.in.read(); System.exit(0); }

46

Jeli program Master zostanie wywoany za pomoc polecenia


Master 10 20 30

to wykonanie programu spowoduje wyprowadzenie liczby 20. Wykonanie instrukcji


String arg = args[i];

powoduje przypisanie odnonikowi arg odniesienia do obiektu acuchowego zainicjowanego kolejnym argumentem programu. Wykonanie instrukcji
int val = Integer.parseInt(arg);

powoduje przeksztacenie obiektu acuchowego w zmienn o wartoci reprezentowanej przez acuch. Poniewa wymienione przeksztacenie moe spowodowa wysanie wyjtku
NumberFormatException

wic w nagwku funkcji main, wystpuje wymagana fraza throws.

Reprezentowanie tablic
Na rysunku Reprezentowanie tablic pokazano sposb przechowywania w pamici operacyjnej tablic jedno - i dwuwymiarowych o elementach typu podstawowego oraz tablic o elementach typu obiektowego " String", zadeklarowanych i zainicjowanych za pomoc nastpujcych instrukcji.
int vecI[] int arrI[][] String vecS[] = { 10, 20, 30 };

= { { 10, 20, 30 }, { 40, 50, 60 } }; = { "Java", "is", "cool" };

String arrS[][] = { { "Java", "is", "much" }, { "cooler", "than", "C++" } };

47

Rysunek Reprezentowanie tablic


###

vecI 10 20 30 arrI arrI[0] 10 20 30 40 50 60 Java is cool arrS[0][0] arrS[0][1] arrS[0][2] arrS[1][0] arrS[1][1] arrS[1][2] Java is much cooler than C++

arrI[1]

vecS vecS[0] vecS[1] vecS[2] arrS arrS[0]

arrS[1]

###

___________________________________________________________________________ ______________

Obiekty
Obiektem jest zmienna strukturalna stanowica egzemplarz klasy. Podczas definiowania klasy wyszczeglnia si skadniki jej obiektw: pola, konstruktory i metody. Pole jest skadnikiem, ktry okrela waciwoci zmiennej wchodzcej w skad obiektu . Konstruktor jest skadnikiem, ktry okrela sposb inicjowania obiektu klasy. Metoda jest skadnikiem, ktry okrela operacj jak mona wykona na obiekcie klasy. Uwaga: Definicja klasy moe ponadto zawiera definicje funkcji i zmiennych statycznych. Zmienne i funkcje statyczne nie wchodz w skad poszczeglnych obiektw klasy, ale s wsplne wszystkim jej obiektom. Przykad Klasa Cplx
class Cplx { double re = 0, // im = 0; // static int count = 0; // Cplx(int rePar, double imPar) // { re = rePar; im = imPar; count++; } void outCplx() // { System.out.println("(" + re + } static void outCount() // { System.out.println(count); } } pole pole zmienna konstruktor

metoda "," + im + ")"); funkcja

48

Klasa Cplx opisuje rodzin obiektw reprezentujcych liczby zespolone o czci rzeczywistej re i urojonej im. W kadym obiekcie klasy Cplx wystpuj zmienne opisane przez pola re i im oraz jeden konstruktor i jedna metoda. Zmienna count oraz funkcja outCount jest wsplna wszystkim obiektom klasy Cplx. Skadniki te wystpuj poza wszystkimi obiektami klasy.

Tworzenie obiektw
Utworzenie obiektu odbywa si za pomoc wyraenia fabrykujcego
new Class(arg, arg, arg)

w ktrym Class jest nazw klasy obiektu, a kade arg jest argumentem kojarzonym z odpowiadajcym mu parametrem konstruktora obiektu. Bezporednio po utworzeniu obiektu jest wywoywany konstruktor klasy Class. W jego ciele jest dostpny odnonik this, identyfikujcy wanie utworzony obiekt. Rezultatem operacji new jest odnonik zainicjowany kopi odnonika this. Jeli w klasie obiektu zdefiniowano pole field, to nazw zmiennej wchodzcej w skad sfabrykowanego obiektu, a opisanej przez to pole, jest this.field. Nazw t mona uproci do field tylko wwczas, gdy w miejscu jej wystpienia, deklaracja pola jest widoczna (nie przesonita przez inn deklaracj). Uwaga: Jeli klasa Class nie zawiera definicji ani jednego konstruktora, to jest niejawnie uzupeniana definicj konstruktora domylnego
public Class() { super(); }

Przykad Odnonik this


import java.io.IOException; class Cplx { double re = 0, im = 0; Cplx(int re, double im) { this.re = re; this.im = im; } void out() { System.out.println("(" + re + "," + im + ")"); } } public class Master { public static void main(String args[]) throws IOException { Cplx ref = new Cplx(3, 4); ref.out(); // (3,4) System.in.read(); } }

Opracowanie wyraenia fabrykujcego


new Cplx(3, 4)

powoduje utworzenie obiektu skadajcego si z 2 zmiennych typu "double", utworzenia odnonika this zainicjowanego odniesieniem do obiektu, a nastpnie wywoania konstruktora klasy Cplx z argumentami 3 i 4. 49

Poniewa odnonik this identyfikuje wanie utworzony obiekt, wic this.re jest nazw zmiennej reprezentujcej jego cz rzeczywist, a this.im jest nazw zmiennej reprezentujcej jego cz urojon. W ciele konstruktora zmiennym tym s przypisywane dane o wartociach 3 i 4, okrelonych przez argumenty konstruktora. Poniewa w miejscu wystpienia napisu this.re nie jest widoczna deklaracja pola re (gdy jest przesonita przez deklaracj parametru re), wic uproszczenie this.re do re nie jest dozwolone.

Niszczenie obiektw
Niszczenie obiektw jest automatyczne. Zniszczenie obiektu odbywa si nie wczeniej, ni w chwili, gdy istnieje pewno, e ani jednemu odnonikowi nie jest przypisane odniesienie do obiektu. Przykad Niszczenie obiektw
import java.io.IOException; class Master { public static void main(String args[]) throws IOException { { Cplx ref = new Cplx(1, 2); } Cplx ref = new Cplx(3, 4); ref = new Cplx(5, 6); ref.out(); // (5, 6) ref = null; ref.out(); // bd (NullPointerException) System.out.println("Done"); System.in.read(); } }

Poniewa po wykonaniu instrukcji


{ Cplx ref = new Cplx(1, 2); }

nie istnieje ju odnonik identyfikujcy obiekt Cplx(1, 2), wic w dowolnej chwili obiekt ten moe by zniszczony. Poniewa po wykonaniu instrukcji
ref = new Cplx(5, 6);

nie istnieje ju odnonik identyfikujcy obiekt Cplx(3, 4), wic w dowolnej chwili obiekt ten moe by zniszczony. Analogicznie, po wykonaniu instrukcji
ref = null;

moe by zniszczony obiekt Cplx(5, 6). W miejscu wykonania instrukcji


ref.out();

zostanie wysany wyjtek klasy NullPointerException. Poniewa wyjtek nie jest obsuony (brak instrukcji try), wic nastpi zakoczenie wykonywania programu, bez wykonania instrukcji
System.out.println("Done");

50

Fabrykowanie obiektw
Obiekty mona fabrykowa za pomoc operacji new oraz za pomoc metod fabrykujcych, jak na przykad newInstance. Metoda newInstance jest wywoywana na rzecz obiektu opisujcego klas, ktrej obiekt ma zosta sfabrykowany.
public Class getClass()

Metoda zwraca odnonik do obiektu opisujcego klas tego obiektu, na rzecz ktrego j wywoano.
public static Class forName(String className) throws ClassNotFoundException

Metoda zwraca odnonik do obiektu opisujcego klas o nazwie identyfikowanej przez className.
public Object newInstance() throws InstantiationException, IllegalAccessException

Metoda zwraca odnonik do obiektu klasy opisanej przez obiekt klasy Class na rzecz ktrego j wywoano. Sfabrykowany obiekt jest inicjowany przez konstruktor domylny. Przykad Fabrykowanie obiektw
import java.io.IOException; public class Master { public static void main(String args[]) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { Class childObj = Class.forName("Child"); Object child = childObj.newInstance(); Child isa = (Child)child; System.out.println(isa.getName() + " is " + isa.getAge()); System.in.read(); } } class Child { private String name = "Isabel"; private int age; public Child() { age = 13; } public String getName() { return name; } public int getAge() { return age; } }

Wykonanie programu powoduje wyprowadzenie napisu


Isabel

Wywoywanie procedur
Wywoaniami procedur s wywoania konstruktorw, metod i funkcji. Konstruktor wywouje si na rzecz obiektu utworzonego podczas opracowania wyraenia fabrykujcego albo z wntrza innego konstruktora, na rzecz wanie inicjowanego obiektu. Metod wywouje si na rzecz obiektu identyfikowanego przez odnonik. Funkcj wywouje si w oderwaniu od jakiegokolwiek obiektu.

51

Jeli w ciele klasy zdefiniowano wicej ni jedn procedur o takiej samej nazwie, to jest wywoywana ta, do ktrej parametr w najlepiej pasuj podane argumenty wywoania. W szczeglnoci, jeli klasa zawiera wicej ni jeden konstruktor, to wywouje si ten, ktrego liczba parametrw jest rwna liczbie argumentw wywoania. Na przykad
String isa = "Isabel"; System.out.print(isa.toUpperCase()); // ISABEL

Metod toUpperCase wywoano na rzecz obiektu identyfikowanego przez odnonik isa.

Inicjowanie parametrw i rezultatw


W ramach wywoania procedury odbywa si kojarzenie jej parametrw z argumentami wywoania. Kade skojarzenie polega na zainicjowaniu parametru wartoci kojarzonego z nim argumentu. Jeli rezultat procedury jest typu rnego od "void", to w chwili wykonania instrukcji powrotu, inicjuje si go wartoci wyraenia podanego w tej instrukcji. Uwaga: Parametr jest lokaln zmienn procedury, a zmiana wartoci parametru nie ma adnego wpywu na warto skojarzonego z nim argumentu. Przykad Inicjowanie parametrw i rezultatu
import java.io.IOException; class Child { String name; int age = 0; Child(String name, int age) { this.name = name; this.age = age; } Child(String name) { this.name = name; } void setAge(int age) { this.age = age; } int getAge() { return age; } void show() { if(age != 0) System.out.println(name + " is " + age); else System.out.println(name + "! How old are you?"); } } public class Master { public static void main(String args[]) throws IOException { Child tom = new Child("Tom"); tom.show(); tom.setAge(12); tom.show(); Child isa = new Child("Isa", 13); isa.show(); System.in.read(); }

52

Podczas wykonania instrukcji


tom.setAge(12);

nastpuje skojarzenie parametru age metody setAge z argumentem 12, a w ramach tej czynnoci niejawne wykonanie instrukcji
age = 12

Podczas wykonania instrukcji


return age;

nastpuje skojarzenie rezultatu metody getAge ze zmienn reprezentowan przez wyraenie age, a w ramach tej czynnoci niejawne wykonanie instrukcji
res = age;

w ktrej res reprezentuje rezultat funkcji. Wykonanie programu powoduje wyprowadzenie napisu
Tom! How old are you? Tom is 12 Isa is 13

Wywoywanie konstruktorw
Konstruktor jest wywoywany podczas opracowywania wyraenia fabrykujcego
new Class(arg, arg, ... , arg)

w ktrym Class jest nazwa klasy, a kade arg jest argumentem wywoania. Ponadto, ale tylko w ciele konstruktora i jako jego pierwsza instrukcja wyraeniowa, mog by uyte wywoania
this(arg, arg, ... , arg)

oraz
super(arg, arg, ... , arg)

Pierwsze z nich jest wwczas wywoaniem innego konstruktora tej samej klasy, a drugie wywoaniem konstruktora jej nadklasy. Przykad Wywoywanie konstruktorw
import java.io.IOException; class Person { String name; int age; Person(String { this.name age = -1; } Person(String { this.name this.age } }

name) = name; // this.age = -1; name, int age) = name; = age;

class Woman extends Person { Person husband = null; Woman(String name, int age) {

53

super(name, age); } Woman(String name, int age, Person husband) { this(name, age); this.husband = husband; } } class Master { public static void main(String args[]) throws IOException { Person john = new Person("John Smith", 40); Woman mary = new Woman("Mary Smith", 30, john); System.in.read(); } }

Wykonanie instrukcji
super(name, age);

powoduje wywoanie dwuparametrowego konstruktora klasy Person. Wykonanie instrukcji


this(name, age);

powoduje wywoanie dwuparametrowego konstruktora klasy Woman.

Wywoywanie metod
Wywoanie metody ma posta
ref.name(arg, arg, ... , arg)

albo
super.name(arg, arg, ... , arg)

w ktrej ref jest odnonikiem identyfikujcym obiekt, name jest nazw metody widocznej w klasie obiektu, sowo kluczowe super okrela, e chodzi o metod nadklasy, a kade arg jest argumentem wywoania. Uwaga: Jeli ref jest odnonikiem this, a w miejscu wywoania jest widoczna definicja metody name, to wywoanie mona uproci do
name(arg, arg, ..., arg)

Takie samo uproszczenie mona zastosowa do wywoania ze sowem kluczowym super. W chwili wywoania metody kojarzy si kady z jej parametrw z odpowiadajcym mu argumentem, a nastpnie tworzy odnonik this i inicjuje go odniesieniem do obiektu na rzecz ktrego odbywa si wywoanie. Po wykonaniu tych czynnoci wykonuje si ciao metody name. Uwaga: Jeli odnonik ref jest typu "Class", to w klasie Class musi by widoczna metoda name. Podczas wykonania programu typ odnonika jest nieistotny: wywouje si metod name widoczn w klasie obiektu identyfikowanego przez odniesienie przypisane odnonikowi ref. Przykad Wywoywanie metod
import java.io.IOException; class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age;

54

} void setAge(int age) { System.out.println("In Person.setAge"); this.age = age; } void showAge() { System.out.println(age); } } class Woman extends Person { Person husband = null; Woman(String name, int age, Person husband) { super(name, age); this.husband = husband; } void setAge(int age) { System.out.println("In Woman.setAge"); super.setAge(age); } } class Master { public static void main(String args[]) throws IOException { Woman mary = new Woman("Mary Smith", 30, null); Person ref = mary; ref.setAge(32); ref.showAge(); // 32 System.in.read(); } }

Odnonik mary jest typu "Woman". Przypisano mu odniesienie do obiektu klasy Woman. Odnonik Person jest typu "Person". Przypisano mu odniesienie do obiektu klasy Woman. Poniewa wywoanie metody setAge odbywa si na rzecz obiektu mary klasy Woman, a nie na rzecz obiektu klasy Person, wic wykonanie instrukcji
ref.setAge(32);

powoduje wywoanie metody setAge klasy Woman, a nie metody setAge klasy Person. Natomiast wykonanie w ciele metody Woman.setAge instrukcji
super.setAge(age);

powoduje wywoanie metody Person.setAge. Wykonanie programu powoduje wyprowadzenie napisu


In Woman.setAge In Person.setage 32

Wywoywanie funkcji
Wywoanie funkcji klasy Class ma posta
Class.name(arg, arg, ..., arg)

w ktrej name jest nazw funkcji widocznej w klasie Class, a kade arg jest argumentem wywoania. Jeli wywoanie znajduje si w zakresie deklaracji funkcji name, to mona je uproci do 55

name(arg, arg, ..., arg)

W chwili wywoania funkcji kojarzy si kady z jej parametrw z odpowiadajcym mu argumentem, a nastpnie wykonuje ciao funkcji name. Dla funkcji nie tworzy si odnonika this, a wic w kadym zawartym w niej odwoaniu do niestatycznego skadnika klasy musi wystpi jawny odnonik. Uwaga: Z powodu braku odnonika this, odwoanie do statycznego skadnika klasy jest zazwyczaj kwalifikowane nazw klasy. Jest to zbyteczne jeli w punkcie odwoania skadnik jest widoczny. Przykad Wywoywanie funkcji
import java.io.IOException; public class Master { static void printLine(String line) { System.out.println(line); } void printStars(int count) { for(int i = 1; i <= count ; i++) System.out.print("*"); System.out.println(); } public static void main(String args[]) throws IOException { String name = "John"; Master.printLine(name); // printLine(name) Master refObj = new Master(); refObj.printStars(3); printLine(name); // Master.printLine(name) System.in.read(); } }

Poniewa wywoanie
Master.printLine(name)

znajduje si w zakresie deklaracji statycznej funkcji printLine, wic mona je uproci do


printLine(name)

Wywoanie
refObj.printStars(3)

nie moe by uproszczone do


printStars(3)

ani zastpione wywoaniem


Master.printStars(3)

poniewa skadnik printStars nie jest statyczny. Wykonanie programu powoduje wyprowadzenie napisu
John *** John

56

Wywoanie rekurencyjne
Wywoanie metody i funkcji moe by rekurencyjne. Rekurencja polega na tym, e jeszcze przed zakoczeniem wykonania pewnej procedury, jest ona wywoywana ponownie. Taki sposb postpowania moe znakomicie uproci zakodowanie procedury, jednak w pewnych warunkach moe spowodowa wyduenie czasu jej wykonywania lub zwikszenie iloci wymaganych przez ni zasobw. Przykad Wyznaczenie potgi Rozwizanie iteracyjne
int powerOf2(int pow) { int power = 1; while(pow-- != 0) power += power; return power; }

Rozwizanie rekurencyjne
int powerOf2(int pow) { if(pow == 0) return 1; else { int halfPower = powerOf2(pow-1); return halfPower + halfPower; } }

Przetwarzanie obiektw
Przetwarzanie obiektw polega na ich tworzeniu oraz na wywoywaniu metod na rzecz obiektw. Przetwarzanie obiektw za pomoc funkcji wymaga dostarczenia im odnonikw do obiektw. W ciele funkcji taki odnonik moe by uyty do wywoania metody na rzecz obiektu. Nastpujcy program ilustruje zasad utworzenia stosu. Elementami stosu s obiekty klasy Item zawierajce zmienne typu "int". Uwaga: Stosem jest kolekcja, do ktrej mona dokada elementy, ale z ktrej mona je wyjmowa tylko w kolejnoci odwrotnej do dokadania. Przykad Projektowanie stosu
import java.io.IOException; class Item { Item refNext = null; int value; Item(int val) { value = val; } } class Stack { Item refHead = null; void push(int val) { Item refNew = new Item(val); refNew.refNext = refHead; refHead = refNew; } int pop() { if(refHead == null) throw new RuntimeException();

57

else { int res = refHead.value; refHead = refHead.refNext; return res; } } } public class Master { public static void main(String args[]) throws IOException { int vec[] = { 10, 20, 30, 40 }; Stack stackA = new Stack(), stackB = new Stack(); for(int i = 0; i < vec.length ; i++) stackA.push(vec[i]); for(int i = 0; i < vec.length ; i++) { int val = stackA.pop(); System.out.print(val + " "); stackB.push(val); } System.out.println(); for(int i = 0; i < vec.length ; i++) System.out.print(stackB.pop() + " "); System.out.println(); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


40 30 20 10 10 20 30 40

Przetwarzanie klas
Warunkiem utworzenia obiektu jest istnienie definicji jego klasy. Definicje klas s adowane dynamicznie w chwili gdy po raz pierwszy zaistnieje potrzeba utworzenia obiektu. Poniewa adowanie moe odbywa si z sieci rozlegej, co jest obarczone ryzykiem zaadowania klasy naruszajcej bezpieczestwo systemu adujcego, stosuje si szereg zabezpiecze eliminujcych to zagroenie. W celu wdroenia zabezpiecze adowanie klas odbywa si pod nadzorem zarzdcy adowania (Class Loader), a wykonywanie Bkodu pod nadzorem zarzdcy ochrony (Security Manager). Zarzdca adowania dokonuje weryfikacji klasy oraz sprawdza poprawno jej powiza z uprzednio zaadowanymi klasami. Zarzdca ochrony przeprowadza dynamiczn kontrol uprawnie programu do wykonywania niebezpiecznych dla Systemu czynnoci (np. apletowi zezwala na wykonywanie operacji wejcia-wyjcia tylko w odniesieniu do komputera z ktrego zaadowano jego klas). Oba te mechanizmy cznie uniemoliwiaj wprowadzenie do systemu programw, ktre mogyby wymkn si spod jego kontroli. Uwaga: Zainstalowanie zarzdcy ochrony jest wykonywane jednokrotnie dla danej aplikacji. Jeli jest ni przegldarka (np. Netscape), to nie moe by zmienione przez wrogi aplet adowany podczas nawigowania po stronach WWW.

Weryfikacja
Weryfikacja polega na sprawdzeniu, czy B-kod klasy jest waciwie uformowany, czy zawiera odpowiedni tablic symboli oraz czy spenia wymagania syntaktyczne okrelone w specyfikacji jzyka, w tym czy zawiera wycznie dopuszczalne kody operacji, przeniesienia sterowania tylko do pocztku instrukcji oraz waciwe sygnatury procedur.

Przygotowanie
58

Przygotowanie polega na przydzieleniu pamici dla zmiennych statycznych oraz na przypisaniu im wartoci domylnych (np. odnonikom wartoci null, a zmiennym arytmetycznym wartoci 0).

Zwizanie
Zwizanie polega na zastpieniu odwoa symbolicznych do klas, interfejsw, zmiennych i pl odwoaniami bezporednimi, wykorzystujcymi adresy Maszyny Wirtualnej. Podczas zwizywania bada si rwnie, czy zaadowana klasa zawiera wszystkie wymagane skadniki oraz czy s respektowane prawa dostpu do skadnikw.

Zainicjowanie
Zainicjowanie skada si z przypisania wartoci pocztkowych zmiennym statycznym klasy oraz z wykonania kodu jej inicjatorw. Uwaga: Zainicjowanie klasy jest wykonywane dopiero po zweryfikowaniu i zaadowaniu nadklasy danej klasy. Opracowywanie inicjatorw zmiennych statycznych oraz inicjatorw klasy odbywa si w kolejnoci ich wystpienia w klasie.

Zmienne statyczne
Zmienn statyczn jest zmienna zadeklarowana ze specyfikatorem static. Taka zmienna nie jest elementem obiektu, ale jest wsplna wszystkim obiektom klasy. Istnieje nawet wwczas gdy nie utworzono ani jednego obiektu jej klasy. Na przykad
class Master { static int var = 12; // ... }

Zmienna statyczna var jest inicjowana podczas inicjowania klasy.

Inicjatory klasy
Inicjatorem klasy jest fraza
static Block

w ktrej Block jest instrukcj grupujc. Opracowanie inicjatora skada si z wykonania zawartej w niej instrukcji grupujcej. Na przykad
import java.io.IOException; class Master { public static void main(String args[]) throws IOException { System.in.read(); } static int var; static { var = 12; System.out.println("Variable var initialized"); } // ... static { var++; System.out.println("Variable var reinitialized"); } }

Wykonanie programu powoduje wyprowadzenie napisu


Variable var initialized

59

Variable var reinitialized

Aktywne uycie
Klasa, ktrej zaadowanie jest niezbdne do dalszego wykonania programu jest uznawana za aktywnie uyt. Strategia ograniczenia si do adowania klas aktywnie uytych, dobrze nadaje si do programowania w Internecie, poniewa wyklucza adowanie klas, ktre podczas pewnych wykona programu s dla niego cakowicie zbdne. Uwaga: Za poprawn uznaje si implementacj, w ktrej wszystkie zwizania klas, s dokonywane jeszcze przed podjciem wykonywania programu. Przykad Aktywne uycie
import java.io.IOException; class Point { int x, y; static int count = 0; static { System.out.println("Point initialized"); } Point() { x = y = -1; } } class Point3d extends Point { static { System.out.println("Point3d initialized"); } int z; } public class Master { public static void main(String args[]) throws IOException { Point3d spacePoint; spacePoint = new Point3d(); // ... System.in.read(); } }

Wykonanie instrukcji
Point3d spacePoint;

powoduje utworzenie zmiennej spacePoint, ale nie wymaga zaadowania klasy Point3d, poniewa nie istnieje jeszcze potrzeba utworzenia obiektu tej klasy. Opracowanie operacji
new Point3d()

wymaga zaadowania klasy Point3d. W ramach adowania klasy Point3d jest wykonywana jej weryfikacja, przygotowanie i zwizanie. Tu przed zainicjowaniem klasy jest adowana jej nadklasa Point. W ramach adowania klasy Point s wykonywane identyczne czynnoci jak dla klasy Point3D, ale przed jej zainicjowaniem jest adowana i inicjowana jej nadklasa Object. Po zaadowaniu i zainicjowaniu klasy Object jest inicjowana klasa Point. Powoduje to przypisanie zmiennej var wartoci pocztkowej 0 oraz wykonanie inicjatora 60

static { System.out.println("Point initialized"); }

W analogiczny sposb jest inicjowana klasa Point3D. Wykonanie programu powoduje wyprowadzenie napisu
Point initialized Point3d initialized

_________________________________________________________________________________________

Strumienie
Strumieniem wejciowym jest sekwencja danych pochodzca z pliku, z pamici operacyjnej, albo z urzdzenia. Dane maj zazwyczaj posta sekwencji bajtw, ale za pomoc metod takich predefiniowanych klas wejciowych jak StreamTokenizer i StringTokenizer mog by interpretowane jako cigi leksemw. Strumieniem wyjciowym jest sekwencja danych wysyana do pliku, do pamici operacyjnej, albo do urzdzenia. Wysyane dane maj posta sekwencji bajtw, ale za pomoc predefiniowanej klasy wyjciowej PrintStream mog by przeksztacane w cigi znakw.

Klasa FileInputStream
Klasa FileInputStream umoliwia wykonywanie operacji wprowadzania danych na obiektach reprezentujcych strumienie wejciowe. Wykonanie operacji
new FileInputStream(fileName)

w ktrej fileName jest wyraeniem typu "String" okrelajcym nazw pliku, powoduje utworzenie obiektu reprezentujcego strumie zwizany z plikiem o podanej nazwie. Uwaga: Podczas wykonania operacji moe by wysany wyjtek klasy FileNotFoundException albo IOException.

Klasa FileOutputStream
Klasa FileOutputStream umoliwia wykonywanie operacji wyprowadzania danych na obiektach reprezentujcych strumienie wyjciowe. Wykonanie operacji
new FileOutputStream(fileName)

w ktrej fileName jest wyraeniem typu "String" okrelajcym nazw pliku, powoduje utworzenie obiektu reprezentujcego strumie zwizany z plikiem o podanej nazwie. Uwaga: Podczas wykonania operacji moe by wysany wyjtek klasy IOException. Przykad Kopiowanie pliku
import java.io.*; public class Master { static String fileName = "c:\\autoexec.bat"; public static void main(String args[]) throws IOException { FileInputStream inp; try {

61

inp = new FileInputStream(fileName); } catch(FileNotFoundException e) { System.out.println("File " + fileName + " not found"); System.in.read(); return; } FileOutputStream out = new FileOutputStream("auto.bat"); int chr, count = 0; while((chr = inp.read()) != -1) { out.write(chr); count++; } System.out.println("Done! " + count + "chars copied"); System.in.read(); } }

Wykonanie programu powoduje skopiowanie pliku c:\autoexec.bat do pliku auto.bat. Plik auto.bat zostanie umieszczony w katalogu biecym, to jest w tym katalogu, z ktrego pochodzi B-kod aplikacji. Badanie koca pliku identyfikowanego przez odnonik inp naley wykona przez sprawdzenie, czy wprowadzony kod znaku jest rny od -1 (a nie przez sprawdzenie, czy zosta wysany wyjtek klasy IOException). Z tego powodu zmienna chr musi by typu "int".

Klasa StreamTokenizer
Klasa StreamTokenizer umoliwia wprowadzanie leksemw ze strumienia wejciowego skojarzonego z plikiem. Wykonanie operacji
new StreamTokenizer(fileStream)

w ktrej fileStream jest wyraeniem typu "FileInputStream", powoduje utworzenie obiektu, za porednictwem ktrego mona ze strumienia pobiera kolejne leksemy. Uwaga: W celu przygotowania si do pobierania leksemw ze standardowego strumienia wejciowego (domylnie: z klawiatury) naley wykona operacj
new StreamTokenizer(System.in)

a w celu przekazania informacji o kocu strumienia wejciowego nacisn klawisz Ctrl-Z.


public int nextToken()

Metoda dostarcza symbol albo kod kolejnego leksemu. Jeli dostarczy symbol TT_NUMBER, to leksem jest liczb umieszczon w zmiennej nval. Jeli dostarczy symbol TT_WORD, to leksem jest sowem, odnonik do ktrego jest umieszczony w zmiennej sval. Symbole TT_EOF i TT_EOL oznaczaj odpowiednio: koniec pliku i koniec wiersza.
public void eolIsSignificant(boolean itIs)

Metoda okrela, e maj by rozpoznawane i dostarczane znaki koca wiersza (w przeciwnym razie znak nowego wiersza jest traktowany tak jak inne odstpy).
public void parseNumbers()

Metoda okrela, e maj by rozpoznawane i dostarczane liczby rzeczywiste (to jest napisy skadajce si z ewentualnego znaku minus oraz cyfr i kropki (np. -4.25).
public void quoteChar(int quote)

Metoda okrela kod znaku, ktry ma by uyty jako obustronny ogranicznik acucha znakw zawierajcego odstpy (domylnie nie ma takiego ogranicznika). Po wprowadzeniu takiego acucha metoda nextToken dostarcza kod ogranicznika, a odnonik do acucha jest przypisywany sval. Przykad Wprowadzanie leksemw 62

import java.io.*; public class Master { static String fileName = "c:\\source"; public static void main(String args[]) throws IOException { FileInputStream inp; try { inp = new FileInputStream(fileName); } catch(FileNotFoundException e) { System.out.println("File " + fileName + " not found"); System.in.read(); return; } StreamTokenizer tokens; tokens = new StreamTokenizer(inp); int what, EOF = StreamTokenizer.TT_EOF, EOL = StreamTokenizer.TT_EOL, NUMBER = StreamTokenizer.TT_NUMBER, WORD = StreamTokenizer.TT_WORD; tokens.eolIsSignificant(true); tokens.parseNumbers(); tokens.quoteChar('#'); int lineNo = 1; while((what = tokens.nextToken()) != EOF) { if(what == EOL) System.out.println("\nEnd of line #" + lineNo++ + '\n'); else if(what == NUMBER) System.out.print(tokens.nval + " "); else if(what == WORD) System.out.print(tokens.sval + " "); else if(what == '#') System.out.print(tokens.sval + " ") else System.out.print(what + " "); } System.in.read(); } }

Program analizuje podany plik znakowy, a nastpnie wyprowadza zawarte w nim leksemy. Jeli plik c:\source zawiera napis
12 Isa -4.2e2 Isa#bell#13 $%& #John & Mary# 127

to zostanie wyprowadzony napis


12 Isa -4.2 End of line Isa bell 13 End of line e2 John & Mary 127 #1 $ % & #2

Klasa StringTokenizer
Klasa StringTokenizer umoliwia wprowadzanie leksemw z obiektu acuchowego. Wykonanie operacji
new StringTokenizer(string)

63

w ktrej string jest wyraeniem typu "String", powoduje utworzenie obiektu, za porednictwem ktrego mona z acucha pobiera kolejne leksemy.
public StringTokenizer(String str, String dlm)

Argumentami konstruktora s: acuch dzielony na leksemy ( str) oraz acuch skadajcy si z ogranicznikw leksemw (dlm).
public int countTokens()

Metoda dostarcza liczb leksemw w acuchu.


public boolean hasMoreTokens()

Metoda dostarcza warto true, jeli acuch zawiera jeszcze co najmniej jeden leksem.
public String nextToken() throws NoSuchElementException

Metoda dostarcza kolejny leksem. Przykad Sortowanie imion


import java.io.*; import java.util.*; public class Master { static String string = " Jan Ewa Iza "; static String names[]; public static void main(String args[]) throws IOException { StringTokenizer tokens; tokens = new StringTokenizer(string, " \t\n"); int count = tokens.countTokens(); names = new String[count]; int pos = 0; while(tokens.hasMoreTokens()) { Object obj = tokens.nextToken(); String str = (String)obj; names[pos++] = str; } show(names); sort(names); show(names); System.in.read(); } static void sort(String names[]) { boolean sorted = false; while(!sorted) { for(int i = 0; i < names.length-1 ; i++) { sorted = true; String one = names[i], two = names[i+1]; if(one.compareTo(two) > 0) { names[i] = two; names[i+1] = one; sorted = false; } } } } static void show(String names[]) { for(int i = 0; i < names.length ; i++) System.out.print(names[i] + " "); System.out.println(); } }

Ogranicznikami leksemw s: spacja, tabulacja i koniec wiersza. Wykonanie programu powoduje wyprowadzenie napisu 64

Jan Ewa Iza Ewa Iza Jan

Klasa PrintStream
Klasa PrintStream umoliwia wyprowadzanie cigw znakw do strumienia wyjciowego. Wykonanie operacji
new PrintStream(stream)

w ktrej stream jest odnonikiem do obiektu klasy FileOutputStream identyfikujcego plik wyjciowy, powoduje utworzenie obiektu, za porednictwem ktrego mona do tego pliku wysya cigi znakw.
public public public public public public public public void void void void void void void void print(boolean b) print(char c) print(int i) print(long l) print(float f) print(double d) print(String s) print(Object o)

Metoda wyprowadza warto typu podstawowego albo obiektowego po przetworzeniu jej na cig znakw. Uwaga: Zastpienie identyfikatora print identyfikatorem println powoduje dodatkowo wyprowadzenie znaku koca wiersza.
public void println()

Metoda wyprowadza znak koca wiersza.


public void flush()

Metoda wymiata bufor wyjciowy.


public void close()

Metoda zamyka strumie. Uwaga: Zamknicie strumienia jest wykonywane domylnie w chwili zakoczenia wykonywania programu. Przykad Utworzenie pliku tekstowego
import java.io.*; public class Master { public static void main(String args[]) throws IOException { PrintStream out = new PrintStream( new FileOutputStream( "c:\\auto.bat" ) ); out.println("c:\\mouse.exe /q"); out.println("nc"); out.close(); // zbdne System.in.read(); } }

Wykonanie programu powoduje utworzenie pliku c:\auto.bat zawierajcego napis


c:\mouse.exe /q nc

Klasa plikowa
65

Rwnie czsto jak przesyanie danych, wystpuje potrzeba wykonania operacji na pliku albo katalogu. Do tego celu doskonale nadaje si klasa plikowa File. Metody klasy File umoliwiaj realizowanie zapyta o waciwoci plikw i katalogw. Jedna z metod umoliwia usunicie pliku, ale adna nie pozwala na usunicie katalogu. Uwaga: Jeli nazwa pliku zawiera separatory "\" albo "/", to niezalenie od uytego systemu operacyjnego, kady z nich jest uznawany za poprawny.
public File(String name)

Konstruktor tworzy obiekt plikowy opisujcy plik albo katalog o podanej nazwie.
public boolean exists()

Metoda sprawdza, czy istnieje plik albo katalog identyfikowany przez obiekt plikowy.
public boolean isFile()

Metoda sprawdza, czy obiekt plikowy identyfikuje plik.


public boolean isDirectory()

Metoda sprawdza, czy obiekt plikowy identyfikuje katalog.


public boolean canRead()

Metoda sprawdza, czy plik albo katalog moe by odczytany.


public boolean canWrite()

Metoda sprawdza, czy do pliku albo katalogu mona dokona zapisu.


public boolena mkDir()

Metoda tworzy katalog (wraz z nadkatalogami) o nazwie okrelonej przez obiekt plikowy.
public boolean renameTo(File trg)

Metoda zmienia nazw pliku albo katalogu na podan.


public boolean delete()

Metoda usuwa plik. Przykad Klasa plikowa


import java.io.*; public class Master { public static void main(String args[]) throws IOException { String path, name; if(args.length != 2) { System.out.println("Please supply Path & Name"); return; } path = args[0]; name = args[1]; String pathName = path + name; File file = new File(pathName); if(!file.exists()) throw new FileNotFoundException(pathName); if(file.isFile()) { if(!file.canRead()) { System.out.println( "File " + pathName + " is not readable" ); return; } else { FileInputStream source = new FileInputStream(pathName); byte buffer[] = new byte[1024]; while(true) {

66

int byteCount = source.read(buffer); if(byteCount == -1) break; System.out.write(buffer, 0, byteCount); } } } else { System.out.println( "Directory " + pathName + " contains\n"); String list[] = file.list(); for(int i = 0; i < list.length ; i++) { String fileName = list[i]; System.out.print(fileName); File fullName = new File(pathName + "/" + fileName); if(fullName.isDirectory()) System.out.print("\t(directory)"); System.out.println(); } } System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie zawartoci podanego pliku albo katalogu. Jeli program zostanie wywoany z parametrami okrelajcymi ciek (np. c:\) i nazw pliku albo katalogu (np. psp311), to wyprowadzi na przykad napis
Directory c:\psp311 contains PAINT311.ARJ PAINT311.A01 PAINT311.A02 Paint311 (directory)

67

Cz IV

Programowanie obiektowe

Programowanie obiektowe polega na modelowaniu zjawisk, przedmiotw i poj za pomoc obiektw klas. Od strony kodowania programowanie obiektowe polega na cznym wykorzystaniu hermetyzacji, dziedziczenia i polimorfizmu. Podczas analizy problemu, ktry ma by rozwizany technik programowania obiektowego wyodrbnia si rzeczowniki opisujce modelowane zagadnienie, a nastpnie, dla kadego z nich, tworzy odrbn definicj klasy. W szczeglnoci, jeli zamierza si modelowa zwizki midzy pojazdami, samochodami i silnikami, zaleca si utworzy definicje klas Pojazd (Vehicle), Samochd (Car) i Silnik (Motor), a nastpnie, posugujc si hermetyzacj, dziedziczeniem i polimorfizmem, wyrazi wymagane powizania za pomoc zestawu definicji klas. Przykad Projektowanie klas
import java.io.IOException; public class Master { public static void main(String args[]) throws IOException { Vehicle vehicle = new Car("Bugatti", 400); String maker = vehicle.theMaker(); int cuInch = vehicle.getCU(); System.out.println(maker + " " + cuInch); // ... System.in.read(); } } abstract class Vehicle { abstract public String theMaker(); abstract public int getCU(); // ... } class Car extends Vehicle { private String maker; private Motor motor; public Car(String maker, int cuInch) { this.maker = maker; motor = new Motor(cuInch); } public String theMaker() { return maker; } public int getCU() { return motor.getCU(); } // ... } class Motor { private int cuInch; public Motor(int cuInch) { this.cuInch = cuInch; } public int getCU() { return cuInch; } // ... }

68

Poniewa Samochd jest Pojazdem, a Pojazd ma Silnik, wic zwizek "jest" wyraono za pomoc dziedziczenia klas, a zwizek "ma" za pomoc zawarcia w klasie.

_________________________________________________________________________________________

Hermetyzacja
Hermetyzacja polega na odseparowaniu klas i skadnikw klas od innych klas i ich skadnikw. Moe dotyczy caych klas oraz pl, konstruktorw, metod i funkcji.

Hermetyzacja klas
Kada klasa, a wraz ni jej skadniki, naley do pewnego pakietu. Do okrelenia nazwy pakietu suy deklaracja
package name;

w ktrej name jest nazw pakietu. Deklaracja pakietu musi by pierwsz deklaracj moduu rdowego. Jeli jej nie uyto, to przyjmuje si, e wszystkie klasy moduu nale do pakietu domylnego.

Nazwy klas
Klasy mog by tylko publiczne albo pakietowe. Klasa publiczna jest zadeklarowana ze specyfikatorem public i jest dostpna wszdzie. Klasa pakietowa jest deklarowana bez specyfikatora dostpnoci. Jest ona wwczas dostpna w dowolnym module nalecym do jej pakietu. Jeli klasa Class naley do pakietu package, to jej nazw jest package.Class. W wypadku odwoania si do takiej nazwy, definicja klasy jest poszukiwana w katalogach wymienionych w zmiennej rodowiskowej CLASSPATH, w kolejnoci ich wystpienia. W szczeglnoci, jeli w rodowisku Windows 95 wykonano polecenie
set CLASSPATH=c:\cafe;d:\debug\tests

a w programie wystpuje instrukcja


janb.pkg Chain chain = new janb.pkg.Chain();

to skompilowana definicja klasy Chain jest poszukiwana w katalogu c:\cafe\janb\pkg, a jeli si jej tam nie ma, to w katalogu d:\debug\tests\janb\pkg. Uwaga: Gdyby w rozpatrywanym programie uyto polecenia importu
import janb.pkg.Chain;

albo oglniejszego polecenia


import janb.pkg.*.;

to przytoczon instrukcj mona by uproci do


Chain chain = new Chain();

Przykad Hermetyzacja klas


package janb.pkg; public class Master { // ... } class Slave { // ...

69

Klasy Master i Slave nale do pakietu janb.pkg. Klasa Master jest dostpna wszdzie, natomiast klasa Slave jest dostpna tylko w obrbie klas nalecych do pakietu janb.pkg.

Hermetyzacja skadnikw
Hermetyzacja skadnikw jest okrelona przez specyfikatory: private (prywatny), public (publiczny) i protected (chroniony). Skadnik prywatny jest dostpny tylko w jego klasie macierzystej. Skadnik publiczny jest dostpny wszdzie. Skadnik chroniony jest dostpny w caym pakiecie jego klasy macierzystej oraz w podklasie jego klasy macierzystej (niezalen ie od tego, w jakim umieszczono j pakiecie). Skadnik pakietowy (zadeklarowany bez specyfikatora dostpnoci) jest dostpny w caym pakiecie, do ktrego naley jego klasa. Przykad Hermetyzacja skadnikw
package janb.pkg; class Person { private String name; private int age; public Person(String name, int age) { // ... } protected void setAge(int age) { // ... } static void fun() { // ... } }

Pola name i age s prywatne, konstruktor Person jest publiczny, metoda setAge jest chroniona, a funkcja fun jest pakietowa (dostpna w caym pakiecie janb.pkg).

_________________________________________________________________________________________

Dziedziczenie
Dziedziczenie wyraa si za pomoc frazy extends. Jest ono zawsze publiczne. Kada klasa jest podklas tylko jednej nadklasy. U podstawy hierarchii dziedziczenia znajduje si klasa Object. Poniewa kada klasa rna od Object ma dokadnie jedn nadklas, wic struktura klas jest drzewem. Przykad Dziedziczenie klas
class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } } class Woman extends Person { boolean isMarried; public Woman(String name, int age, boolean isMarried) { super(name, age); this.isMarried = isMarried;

70

// ... } }

Klasa Person jest nadklas klasy Woman. Klasa Woman jest podklas klasy Person. Nadklas klasy Person oraz Woman jest klasa Object. Obiekt klasy Person zawiera dwie zmienne opisane przez pola name i age. Obiekt klasy Woman zawiera takie same zmienne jak obiekt klasy Person oraz dodatkowo, zmienn opisan przez pole isMarried.

_________________________________________________________________________________________

Klasy abstrakcyjne
Klas abstrakcyjn jest klasa zadeklarowana ze specyfikatorem abstract. Jeli pewna klasa zawiera deklaracj metody abstrakcyjnej, to jest metody zadeklarowanej ze specyfikatorem abstract, to musi by jawnie zadeklarowana jako abstrakcyjna. Klasa abstrakcyjna rni si od klasy nieabstrakcyjnej tym, e nie mona tworzy jej obiektw bezporednio, to jest za pomoc operacji new albo za pomoc metody fabrykujcej. Dlatego klasy abstrakcyjne s z reguy dziedziczone przez klasy nieabstrakcyjne. Uwaga: Jeli podklasa klasy abstrakcyjnej nie przedefiniuje wszystkich metod abstrakcyjnych jej nadklasy, to sama staje si klas abstrakcyjn.
public abstract class Shape { float x, y; Shape(float x, float y) { this.x = x; this.y = y; } public abstract double getArea(); float getX() { return x; } float getY() { return y; } } // klasa abstrakcyjna

// metoda abstrakcyjna // metoda nieabstrakcyjna

Klasa Shape zawiera deklaracj metody abstrakcyjnej getArea oraz definicje dwch metod nieabstrakcyjnych. Nie wolno pomin specyfikatora abstract wystpujcego w nagwku definicji klasy.

_________________________________________________________________________________________

Metody abstrakcyjne
W miejscu ciaa metody abstrakcyjnej wystpuje rednik. W jednej z podklas klasy abstrakcyjnej musi dla kadej metody abstrakcyjnej by dostarczona metoda nieabstrakcyjna o identycznej sygnaturze, ktrej ciaem jest instrukcja grupujca. Uwaga: Dwie procedury maj identyczne sygnatury, jeli maj takie same identyfikatory, a ich listy deklaracji parametrw (po usuniciu z nich identyfikatorw) skadaj si z takich samych jednostek leksykalnych. W szczeglnoci, dwie nastpujce procedury, mimo i s istotnie rne (pierwsza jest funkcj, a druga metod) maj identyczne sygnatury
static String proc(int one, int[] two[]) String proc(int uno, int[][] due) abstract class Shape { float x, y; Shape(float x, float y) { this.x = x;

71

this.y = y; } public abstract double getArea(); float getX() { return x; } float getY() { return y; } }

// metoda abstrakcyjna

public class Circle extends Shape { static final double Pi = Math.PI; private float radius; Circle(float x, float y, float radius) { super(x, y); this.radius = radius; } public double getArea() // metoda nieabstrakcyjna { return Pi * radius * radius; } }

W klasie Circle przedefiniowano metod abstrakcyjn getArea klasy Shape. Gdyby klasa Circle nie zawieraa definicji metody getArea, to byaby klas abstrakcyjn.

Zastosowania
Nastpujcy program, implementujcy stos o elementach niejednorodnych ilustruje zasady posugiwania si klasami i metodami abstrakcyjnymi. Przykad Projektowanie stosu
import java.io.IOException; abstract class Item { void out() { System.out.println("Please override me!"); } } class IntItem extends Item { private int value; public IntItem(int val) { value = val; } void out() { System.out.print(value + " "); } } class DblItem extends Item { private double value; public DblItem(double val) { value = val; } void out() { System.out.print(value + " "); }

72

} class Stack { private Item vec[]; private int size; private int top = 0; public Stack(int size) { this.size = size; vec = new Item[size]; } void push(Item item) throws StackException { vec[top++] = item; if(top == size) throw new StackException("Stack overflow"); } Item pop() throws StackException { top--; if(top < 0) throw new StackException("Stack underflow"); return vec[top]; } } class StackException extends Exception { public StackException(String cause) { super(cause); } } public class Master { public static void main(String args[]) throws IOException { Stack stack = new Stack(5); try { stack.push(new IntItem(10)); stack.push(new DblItem(2.5)); stack.push(new IntItem(20)); } catch(Exception e) { } while(true) { Item item; try { item = stack.pop(); } catch(StackException e) { break; } item.out(); } System.out.println(); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


20 2.5 10

_________________________________________________________________________________________ 73

Interfejsy
Kada klasa (rna od klasy Object) ma tylko jedn nadklas, ale moe implementowa dowolnie wiele interfejsw. Interfejs jest w istocie klas abstrakcyjn, zawierajc tylko definicje statycznych pl ustalonych ( static i final) oraz metod abstrakcyjnych (abstract). Uwaga: Jeli w definicji interfejsu pominie si specyfikatory static, final i abstract, to zostan one domniemane. Przykad Definicja interfejsu
interface Drawable { static final Color red = Color.red; final Color green = Color.green; Color blue = Color.blue; abstract void draw(Graphics gDC); Graphics getDC(); }

Wszystkie 3 pola s statyczne i ustalone. Obie metody s abstrakcyjne.

Implementowanie interfejsu
Implementowanie interfejsu wyraa si za pomoc sowa kluczowego implements. Kademu odnonikowi typu interfejsowego mona przypisa odniesienie do obiektu klasy implementujcej ten interfejs. Interfejs moe zawiera tylko deklaracje metod oraz definicje statycznych zmiennych ustalonych (final). Kady z tych skadnikw klasy jest domylnie publiczny. Klasa, ktra implementuje interfejs musi dostarczy definicje wszystkich jego metod. W przeciwnym razie staje si klas abstrakcyjn. Przykad Implementowanie interfejsu
import java.io.IOException; interface Taxable { double amount(); } interface Eligible { boolean isMarried(); } class Person { private String name; private int age; protected double taxes; public Person(String name, int age) { // ... } // ... } class Woman extends Person implements Taxable, Eligible { private Person husband; public Woman(String name, int age, Person husband) { super(name, age); this.husband = husband; } public double amount() { return taxes; } public boolean isMarried()

74

{ return husband != null; } // ... } public class Master { public static void main(String args[]) { Taxable taxRef; Person john = new Person("John Smith", 40); Woman mary = new Woman("Mary Smith", 20, john); taxRef = mary; double taxes = taxRef.amount(); // ... System.in.read(); } }

Klasa Woman dziedziczy klas Person oraz implementuje interfejsy Taxable i Eligible. Odnonikowi interfejsowemu taxRef przypisano odniesienie do obiektu klasy Woman implementujcej interfejs Taxable. Metod amount wywoano poprzez odnonik typu "Taxable".

Zastosowania
Nastpujcy program, implementujcy stos o elementach niejednorodnych, ilustruje zasad posugiwania si interfejsami. Przykad Projektowanie stosu
import java.io.IOException; interface Stackable { void out(); } class IntItem implements Stackable { private int value; public IntItem(int val) { value = val; } void out() { System.out.print(value + " "); } } class DblItem implements Stackable { private double value; public DblItem(double val) { value = val; } void out() { System.out.print(value + " "); } } class Stack { private Stackable vec[]; private int size; private int top = 0; public Stack(int size) { this.size = size; vec = new Stackable[size]; }

75

void push(Stackable item) throws StackException { vec[top++] = item; if(top == size) throw new StackException("Stack overflow"); } Stackable pop() throws StackException { top--; if(top < 0) throw new StackException("Stack underflow"); return vec[top]; } } class StackException extends Exception { public StackException(String cause) { super(cause); } } public class Master { public static void main(String args[]) throws IOException { Stack stack = new Stack(5); try { stack.push(new IntItem(10)); stack.push(new DblItem(2.5)); stack.push(new IntItem(20)); } catch(Exception e) { } while(true) { Stackable item; try { item = stack.pop(); } catch(StackException e) { break; } item.out(); } System.out.println(); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


20 2.5 10

_________________________________________________________________________________________

Konwersje
Konwersja obiektowa jest przeksztaceniem z jednego typu obiektowego do innego. Jest ona wyraana przez operator konwersji.
(Type)

w ktrym Type jest nazw typu docelowego (np. " Object" albo "String []"). Rezultatem poprawnej konwersji odnonikowej jest odnonik zainicjowany wartoci argumentu. Na przykad
import java.awt.*;

76

import java.applet.*; public class Master { // ... Applet fun(Object obj)

{
return (Applet)(Panel)obj; } }

Wyraenie obj poddano konwersji do typu "Panel", a nastpnie do typu "Applet".

Konwersje poprawne
Konwersja odnonikowa jest poprawna tylko wwczas gdy jest dopuszczalna i wykonalna. Konwersja jest dopuszczalna gdy jest tosamociowa (np. z typu " Vector" do "Vector"), albo gdy polega na przeksztaceniu z klasy do nadklasy (np. z "Vector" do "Object"), z klasy do podklasy (np. z " Object" do "Vector") albo z klasy do implementowanego przez ni interfejsu (np. z " Vector" do "Cloneable"). Konwersja jest wykonalna, gdy jest dopuszczalna, a wyraenie
exp instanceof Type

(por. opis operatora instanceof) ma warto true. Na przykad


String Object city = Vector city = "Warsaw"; obj = (Object)city; (String)obj; vec = (Vector)obj; // bd (konwersja niewykonalna)

Poniewa klasa String jest podklas klasy Object, wic konwersja


(String)obj

jest dopuszczalna. Jest ona wykonalna, poniewa jest dopuszczalna, a wyraenie


obj instanceof String

ma warto true. Konwersja odnonikowa


(Vector)obj

jest dopuszczalna, ale nie jest wykonalna. A zatem jest bdna.

Konwersje standardowe
Konwersj standardow jest kada konwersja, ktra moe by wykonana niejawnie. Do tej kategorii nale konwersje arytmetyczne, acuchowe i obiektowe.

Konwersje arytmetyczne
Standardow konwersj arytmetyczn jest przeksztacenie z typu o wszym zakresie wartoci do typu o szerszym zakresie warto ci (np. z typu "int" do typu "long"). Na przykad
byte b = 12;

77

int i = 12; i = b; b = i;

// i = (int)b; // bd (brak konwersji)

Konwersje acuchowe
Standardow konwersj acuchow jest przeksztacenie z dowolnego typu podstawowego oraz obiektowego do typu " String". Jeli operacja dotyczy zmiennej typu podstawowego, to jest uywana metoda append klasy StringBuffer, a jeli dotyczy zmiennej typu obiektowego, to sposb wykonania konwersji jest okrelony przez jej metod toString. Uwaga: Metoda toString jest zdefiniowana zawsze, poniewa wystpuje w klasie Object. Na przykad
Thread thread = Thread.currentThread(); String var = 4 + "sale" + thread;

Operacja
4 + "sale" + thread

jest wykonywana tak jak operacja


new StringBuffer().append(4). append("sale"). append(thread.toString()). toString()

Konwersje obiektowe
Standardow konwersj obiektow jest przeksztacenie odnonika klasy na odnonik jego nadklasy oraz odnonika klasy na odnonik jej interfejsu. W szczeglnoci tak konwersj jest przeksztacenie kadego odnonika na odnonik klasy Object. Na przykad
import java.io.IOException; class Primary implements Runnable { // ... public void run() { // ... } } class Derived extends Primary { // ... } public class Master { public static void main(String args[]) throws IOException { Primary prm; prm = (Primary)new Derived(); prm = new Derived(); // identyczne z poprzednim Runnable rnb; rnb = (Runnable)prm; rnb = prm;

// identyczne z poprzednim;

rnb = (Runnable)new Derived(); rnb = new Derived(); // identyczne z poprzednim prm = (Primary)rnb; prm = rnb; args = (String [3])args; // bd (brak konwersji) // bd (podano rozmiar)

78

// ... System.in.read(); } }

Poniewa klasa Primary implementuje interfejs Runnable, wic albo musi by abstrakcyjna, albo musi zawiera definicj metody run (wybrano to drugie). Bd w operacji przypisania
prm = rnb

wynika z tego, e nie istnieje konwersja standardowa z typu " Runnable" do typu "Primary". Bd w operacji
(String [3])args

polega na tym, e uyto rozmiaru tablicy.

Konwersje statyczne
Kada konwersja odnonika na odnonik jego nadklasy albo podklasy jest konwersj poprawn statycznie, ale nie musi by konwersj poprawn dynamicznie (tj. podczas wykonania programu). Przykad Konwersje statyczne
String str = "Hello"; Object obj = str; str = (String)obj; // Object obj = (Object)str;

Poniewa klasa String jest podklas klasy Object, wic wyraenie str typu "String" moe by przeksztacone w wyraenie typu "Object", a wyraenie obj typu "Object" moe by przeksztacone w wyraenie typu " String".

Konwersje dynamiczne
Konwersja odnonika na inny odnonik jest poprawna dynamicznie tylko wwczas, gdy klasa odniesienia przypisanego odnonikowi poddawanemu konwersji jest klas albo podklas odnonika docelowego. Jeli wymaganie to nie jest spenione, to z miejsca konwersji jest wysany wyjtek klasy ClassCastException. Przykad Konwersje dynamiczne
import java.io.IOException; import java.awt.*; import java.applet.*; public class Master { public static void main(String args[]) { Panel panel; Applet applet; panel = new Applet(); applet = (Applet)panel; panel = new Panel(); applet = (Applet)panel; // bd dynamiczny // ... System.in.read(); } }

Poniewa klasa Applet jest podklas klasy Panel, wic obie instrukcje
applet = (Applet)panel;

s poprawne statycznie. 79

Poniewa podczas wykonywania drugiej instrukcji


applet = (Applet)panel;

odnonik panel nie identyfikuje obiektu klasy Applet, wic podczas prby wykonania konwersji
(Applet)panel

zostanie wysany wyjtek klasy ClassCastException.

Operator pochodzenia
Rozstrzygnicie o tym, czy konwersja doprowadzi, czy nie doprowadzi do wysania wyjtku klasy ClassCastException umoliwia operator pochodzenia. Operacja pochodzenia ma posta
exp instanceof Class

w ktrej exp jest wyraeniem odnonikowym, a Class jest identyfikatorem klasy. Rezultatem operacji pochodzenia jest orzecznik, ktry ma warto true tylko wwczas, gdy odnonik exp identyfikuje obiekt klasy Class albo jej podklasy. Przykad Operator pochodzenia
static Applet anApplet(Panel panel) { if(panel instanceof Applet) return (Applet)panel; return null; }

Jeli podczas wykonywania funkcji fun, odnonik panel nie identyfikuje obiektu, ktry jest klasy Applet albo jej podklasy, to funkcja zwraca null.

_________________________________________________________________________________________

Polimorfizm
Kade wywoanie metody jest polimorficzne. Oznacza to, e jest wywoywana metoda widoczna w klasie obiektu identyfikowanego przez odniesienie przypisane odnonikowi, a nie metoda widoczna w klasie odnonika. Przykad Wywoania polimorficzne
interface Taxable { void showTaxes(); } class Person { private double taxes; public Person(String name, int age) { // ... } double getTaxes() { return taxes; } void showTaxes() { // ... } } class Woman extends Person implements Taxable {

80

public Woman(String name, int age) { super(name, age); } public void showTaxes() { // ... } // ... } class Master { void Sub(Person person, Woman woman, Taxable taxes) { person = new Woman("Mary Smith", 20); person.showTaxes(); // ... woman = (Woman)person; taxes = woman; taxes.showTaxes(); // ... double amount; amount = person.getTaxes(); } }

Wykonanie instrukcji
person.showTaxes();

powoduje wywoanie metody showTaxes klasy Woman (a nie metody showTaxes klasy Person). Wykonanie instrukcji
taxes.showTaxes()

powoduje wywoanie metody showTaxes klasy Woman (a nie metody showTaxes interfejsu Taxable). Wykonanie instrukcji
amount = person.getTaxes();

powoduje wywoanie metody getTaxes widocznej w klasie Woman, to jest metody getTaxes klasy Person.

_________________________________________________________________________________________

Klasy
Zasady programowania obiektowego mona zilustrowa projektami klas do przechowywania acuchw znakw ( CString) i dynamicznych wektorw (CVector).

Klasa CString
Klasa CString umoliwia tworzenie obiektw identyfikujcych acuchy znakw o dowolnym rozmiarze. W odrnieniu od predefiniowanej klasy String, ktrej obiekty identyfikuj wektory o elementach 2 -bajtowych, obiekty klasy CString identyfikuj wektory o elementach 1-bajtowych, a wic zapewniaj oszczdniejsz implementacj.
class CString implements Cloneable { private int len; private byte ref[]; public CString(String str) { len = str.length(); ref = new byte [len+1]; for(int i = 0; i < len ; i++) ref[i] = (byte)str.charAt(i); ref[len] = 0; }

81

public char charAt(int i) throws IndexOutOfBoundsException { if(i < 0 || i >= len) throw new IndexOutOfBoundsException(); return (char)ref[i]; } public String toString() { String str = ""; for(int i = 0; i < len ; i++) str += (char)ref[i]; return str; } public int compareTo(CString str) { return toString().compareTo(str.toString()); } public boolean equals(Object obj) { if(obj instanceof String) { String str = ((String)obj).toString(); return toString().compareTo(str) == 0; } else return false; } public Object clone() throws CloneNotSupportedException { Object clone = super.clone(); String str = toString(); CString string = new CString(str); ((CString)clone).ref = string.ref; return clone; } public void set(CString str) throws CloneNotSupportedException { CString string = (CString)str.clone(); len = string.len; ref = string.ref; } public void set(String str) throws CloneNotSupportedException { CString string = new CString(str); set(string); } }

Przykad Uycie klasy CString


import java.io.IOException; public class Master { public static void main(String args[]) throws IOException, CloneNotSupportedException { CString greet = new CString("Hello world"); System.out.println(greet); int i = 0; while(true) { try { char chr = greet.charAt(i++); System.out.print(chr); } catch(IndexOutOfBoundsException e) { break; } } System.out.println(); CString string = (CString)greet.clone(); System.out.println(string.equals(greet.toString()));

82

greet = new CString("Hello"); System.out.println(greet); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


Hello world Hello world true Hello

Klasa CVector
Klasa CVector umoliwia tworzenie obiektw identyfikujcych dynamiczne wektory o elementach pomocniczej klasy CDouble. Klasa ta stanowi otoczk dla zmiennych typu "double".
public class CVector { private int size = 1; private int len = 0; private CDouble ref[]; public CVector() { ref = new CDouble [size]; } CDouble refAt(int i) { return ref[i]; } CVector append(double val) { if(len >= size) { CDouble ref[] = new CDouble [2 * size]; for(int i = 0; i < size ; i++) ref[i] = this.ref[i]; size *= 2; this.ref = ref; } ref[len++] = new CDouble(val); return this; } } class CDouble { private double value; public CDouble(double val) { value = val; } public double get() { return value; } public void set(double val) { value = val; } }

Przykad Uycie klasy CVector


import java.io.IOException; import java.util.*; public class Master { private static final int size = 5; public static void main(String args[]) throws IOException

83

{ CVector vec = new CVector(); for(int i = 0; i < size ; i++) vec.append(10 * (i+1)); for(int i = 0; i < size ; i++) vec.refAt(i).set(-vec.refAt(i).get()); for(int i = 0; i < size ; i++) System.out.print(vec.refAt(i).get() + " "); System.out.println(); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


-10 -20 -30 -40 -50

_________________________________________________________________________________________

Kolekcje
Nastpujcy program, w ktrym zdefiniowano interfejs Measurable, kolekcj Shapes oraz iterator ShapesEnumerator ilustruje zasady programowania obiektowego. Wymienione klasy umoliwiaj przechowywanie obiektw podklas klasy Shape, bezporednio albo porednio implementujcych interfejs Measurable. Przykad Projektowanie kolekcji
interface Measurable { double getArea(); String kindOf(); } // wyznaczenie pola // dostarczenie nazwy

class Shapes { private int noOfSlots = 1; // liczba miejsc private int freeSlot = 0; // pierwsze wolne miejsce Measurable vec[]; // odnoniki do obiektw public Shapes() { vec = new Measurable [noOfSlots]; } public int getFreeSlot() { return freeSlot; } int getNoOfSlots() { return noOfSlots; } Measurable getAt(int pos) { return vec[pos]; } int addShape(Measurable shape) // dodaj obiekt { if(freeSlot >= noOfSlots) { Measurable vecOld[] = vec; int noOfSlotsOld = noOfSlots; noOfSlots <<= 1; // podwj pojemno vec = new Measurable [noOfSlots]; System.arraycopy(vecOld, 0, vec, 0, vecOld.length); } vec[freeSlot] = shape; return freeSlot++; } Measurable remShape(int pos) // usu obiekt throws IndexOutOfBoundsException { Measurable shape = vec[pos];

84

vec[pos] = null; return shape; } double getArea() // wyznacz pole { double total = 0; for(int i = 0; i < freeSlot ; i++) if(vec[i] != null) total += vec[i].getArea(); return total; } void showAll() // poka zawarto { for(int i = 0; i < freeSlot ; i++) { Shape shape = (Shape)vec[i]; if(shape != null) System.out.println( "\t" + shape.kindOf() + " At(" + shape.getX() + "," + shape.getY() + ")" ); } } public final synchronized Enumeration elements() { return new ShapesEnumerator(this); } } class ShapesEnumerator implements Enumeration { private Shapes shapes; private int pos = 0; public ShapesEnumerator(Shapes shapes) { this.shapes = shapes; } public boolean hasMoreElements() { if(pos < shapes.getFreeSlot()) return true; pos = 0; return false; } public Object nextElement() { if(hasMoreElements()) return shapes.getAt(pos++); throw new NoSuchElementException("ShapesEnumerator"); } }

Zdefiniowane powyej klasy kolekcyjne i iteracyjne zostay uyte w nastpujcym programie. W programie tym, podklasami klasy Shape, implementujcymi interfejs Measurable s Circle i Square.
import java.io.*; import java.util.*; abstract class Shape implements Measurable { private int x = 0, y = 0; Shape() { } Shape(int x, int y) { this.x = x; this.y = y; } int getX() { return x;

// wsprzdne rodka

85

} int getY() { return y; } public abstract double getArea(); public String kindOf() { return getClass().toString(); } }

// powierzchnia obiektu // nazwa obiektu

class Circle extends Shape { // klasa okrgw public static final double Pi = Math.PI; private int radius; public Circle(int x, int y, int radius) { super(x, y); this.radius = radius; } public String kindOf() { return "Circle"; } public double getArea() { return Pi * radius * radius; } } class Square extends Shape { // klasa kwadratw private int side; public Square(int x, int y, int side) { super(x, y); this.side = side; } public String kindOf() { return "Square"; } public double getArea() { return (double)side * side; } } public class Master { public static void main(String args[]) throws IOException { Circle aCircle = new Circle(10, 10, bCircle = new Circle(20, 20, cCircle = new Circle(30, 30, Square aSquare = new Square(40, 40, bSquare = new Square(50, 50, Shapes shapes = new Shapes(); int pos; // obiekty // shapes.addShape(aCircle); // pos = shapes.addShape(bCircle); // shapes.remShape(pos); // pos = shapes.addShape(cCircle); // shapes.addShape(aSquare); // shapes.remShape(pos); // pos = shapes.addShape(bSquare); // shapes.remShape(pos); //

1), 2), 3); 5), 5);

// // // // //

aC bC cC aS bS

w kolekcji ========== aC aC, bC aC aC, cC aC, cC, aS aC, aS aC, aS, bS aC, aS

System.out.println("Shapes in collection:\n"); shapes.showAll(); System.out.println("\nTotal area: " + shapes.getArea());

86

System.out.println("\nCleaning the collection:\n"); ShapesEnumerator shapesEnum = new ShapesEnumerator(shapes); pos = 0; while(shapesEnum.hasMoreElements()) { Shape shape = (Shape)shapesEnum.nextElement(); if(shape != null) System.out.println( "\tDeleting " + shape.kindOf() + ", Area: " + shape.getArea() ); shapes.remShape(pos++); } System.out.println("\nDone!"); System.in.read(); } }

Program wyprowadza napis pokazany w tabeli Wyniki wykonania. Tabela Wyniki wykonania
### Shapes in collection: Circle At(10,10) Square At(40,40) Total area: 28.1416 Cleaning the collection: Deleting Circle, Area: 3.14159 Deleting Square, Area: 25 Done! ###

87

Cz V

Programowanie zdarzeniowe

Programowanie zdarzeniowe polega na dostarczeniu zestawu procedur, z ktrych po zajciu zdarzenia zewntrznego (klikniciu przycisku myszki, naciniciu klawisza klawiatury), jest wybierana do wykonania ta procedura, ktra zostaa przewidziana do obsugi zdarzenia. Podstawowymi procedurami zdarzeniowymi, w ktre wyposaa si komponenty i pojemniki komponentw (np. przyciski, aplety, ramki) s metody paint i handleEvent. Metoda paint jest wywoywana przez System po utworzeniu pojemnika oraz kadorazowo gdy zawarto pojemnika powinna zosta odtworzona. Z wntrza programu moe by wywoana za pomoc metody repaint. Uwaga: Metoda repaint wywouje metod update, ktra tu przez wywoaniem metody paint czyci obszar pojemnika (wypenia go kolorem ta). Metoda handleEvent jest wywoywana kadorazowo po zajciu zdarzenia zewntrznego. Jeli w klasie pojemnika nie zostanie przedefiniowana, to w zalenoci od rodzaju zdarzenia wywoa takie metody jak action (np. reakcja na kliknicie przycisku), mouseDown (reakcja na nacinicie przycisku myszki), mouseUp (reakcja na zwolnienie przycisku myszki), itp. Uwaga: Jeli zdarzenie dotyczce sterownika (komponentu albo pojemnika) zostao w peni obsuone przez metod (np. handleEvent, action, itp.), to potwierdzeniem tego jest zwrcenie przez ni wartoci true. W przeciwnym razie metoda zwraca warto false. Umoliwia to obsuenie zdarzenia przez pojemnik sterownika.
public void paint(Graphics gDC)

Metoda jest wywoywana przez System, gdy zachodzi potrzeba odtworzenia zawartoci pulpitu.
public void repaint() public void repaint(int x, int y, int w, int h)

Metoda jest apelem o niejawne wywoanie metody update w odniesieniu do caego pulpitu, albo do jego prostoktnej czci okrelonej cznie przez (x,y) i w x h.
public boolean handleEvent(Event evt)

Metoda jest wywoywana przez System, bezporednio po zajciu zdarzenia zewntrznego. Nastpujcy program, pokazany podczas wykonywania na ekranie Propagacja zdarze, ilustruje zasad obsugiwania zdarze. Ekran Propagacja zdarze
### propag.gif

Przykad Propagacja zdarze


import java.io.IOException; import java.awt.*; public class Master extends Frame { static Frame frame; static Button button; public Master(String caption) { super(caption); } public static void main(String args[]) throws IOException { frame = new Master("Frame window"); button = new MyButton("Click me", frame); frame.setLayout(new FlowLayout()); frame.add(button); frame.resize(120, 80); frame.show(); System.out.println("Press Enter to close all"); System.in.read(); System.exit(0); } public boolean action(Event evt, Object arg)

88

{ Graphics gDC = frame.getGraphics(); gDC.drawString("Frame clicked!", 10, 70); return true; } } class MyButton extends Button { Frame frame; MyButton(String caption, Frame frame) { super(caption); this.frame = frame; } public boolean action(Event evt, Object arg) { Graphics gDC = frame.getGraphics(); gDC.drawString("Button clicked!", 10, 50); return false; } }

Kliknicie przycisku powoduje wywoanie metody action klasy MyButton. Poniewa metoda zwraca false, wic zdarzenie propaguje do pojemnika przycisku, ktrym jest okno aplikacji. Pojemnik zwraca warto true, co oznacza, e zdarzenie w peni obsuono.

_________________________________________________________________________________________

Klasa zdarzeniowa
W ciele metody handleEvent jest dostpny odnonik do obiektu klasy Event, zawierajcego szczegowy opis zaistniaego zdarzenia. Wybrany fragment definicji klasy Event przytoczono w tabeli Klasa zdarzeniowa. Tabela Klasa zdarzeniowa
### public class Event extends Object { public int id; // rodzaj zdarzenia public Object target; // odnonik do sterownika public Object arg; // cecha sterownika public long when; // chwila zajcia zdarzenia public int x; // punkt kliknicia (x) public int y; // punkt kliknicia (y) public int key; // kod klawisza public int modifiers; // Ctrl, Shift, Alt, Meta public int clickCount; // licznik klikni public Event evt; // zdarzenie // ... } ###

Nastpujcy program, pokazany podczas wykonania na ekranie Pozdrowienie, wywietla przyciski Greet i Clear. Po klikniciu przycisku jest wywoywana metoda handleEvent. Jeli kliknito przycisk Greet, to wywietla si napis Hello, a jeli kliknito przycisk Clear to nastpuje wyczyszczenie pulpitu ramki. Ekran Pozdrowienie
### sayhello.gif import java.io.IOException; import java.awt.*; public class Master extends Frame { static private Button greetButton, clearButton; String msg = ""; static Frame frame;

89

public static void main(String args[]) throws IOException { frame = new Master(); frame.setLayout(new FlowLayout()); frame.resize(160, 100); frame.show(); System.in.read(); System.exit(0); } Master() { super("Hello"); greetButton = new Button("Greet"); clearButton = new Button("Clear"); add(greetButton); add(clearButton); } public void paint(Graphics gDC) { gDC.drawString(msg, 15, 50); } public boolean handleEvent(Event evt) { if(evt.id == Event.ACTION_EVENT) { if(evt.target == greetButton) { msg = "Hello"; repaint(); // "wywouje" paint return true; } else if(evt.target == clearButton) { msg = ""; repaint(); // "wywouje" paint return true; } } return false; } }

Poniewa przedefiniowano metod handleEvent, wic nie s wywoywane takie metody jak action, mouseDown, mouseUp, itp. Wywoanie metody repaint jest apelem o wywoanie metody paint. System uwzgldni ten apel w najbliszym dogodnym momencie, ale dopiero po zakoczeniu wykonywania procedury wywoujcej.

_________________________________________________________________________________________

Obsugiwanie zdarze
Przedefiniowanie procedury handleEvent stanowi najoglniejszy sposb obsugi zdarze. Nie zawsze jest to jednak konieczne, poniewa w wielu wypadkach wystarczy przedefiniowa procedury obsugi wywoywane przez predefiniowan metod handleEvent. Fragment klasy Component zawierajcej definicj metody handleEvent przytoczono w tabeli Metoda handleEvent. Tabela Metoda handleEvent
### public abstract class Component implements ImageObserver { // ... public boolean handleEvent(Event evt) { switch (evt.id) { case Event.ACTION_EVENT: return action (evt, evt.arg); case Event.MOUSE_DOWN: return mouseDown (evt, evt.x, evt.y); case Event.MOUSE_UP: return mouseUp (evt, evt.x, evt.y); case Event.MOUSE_MOVE: return mouseMove (evt, evt.x, evt.y); case Event.MOUSE_DRAG:

90

return mouseDrag (evt, evt.x, evt.y); case Event.MOUSE_ENTER: return mouseEnter(evt, evt.x, evt.y); case Event.MOUSE_EXIT: return mouseExit (evt, evt.x, evt.y); case Event.KEY_PRESS: case Event.KEY_ACTION: return keyDown (evt, evt.key); case Event.KEY_RELEASE: case Event.KEY_ACTION_RELEASE: return keyUp (evt, evt.key); case Event.GOT_FOCUS: return gotFocus (evt, evt.arg); case Event.LOST_FOCUS: return lostFocus(evt, evt.arg); } return false; } // ... public boolean action(Event evt, Object arg) { return false; } // ... } ###

W metodzie handleEvent s rozpoznawane i wywoywane zdarzenia zwizane z klikniciami przyciskw ( ACTION_EVENT), zdarzenia zwizane z myszk i z klawiatur (np. MOUSE_DOWN i KEY_PRESS) oraz zdarzenia zwizane z przemieszczeniem wyrnienia sterownika (GOT_FOCUS i LOST_FOCUS). Uwaga: W danej chwili moe by wyrniony tylko tylko jeden sterownik. Przemieszczenie wyrnienia moe by wykonane z programu, albo za pomoc klawiszy Tab i Shift-Tab. Po rozpoznaniu zdarzenia jest wywoywana pomocnicza metoda obsugi (np. action, mouseDown, keyPress, gotFocus). Jej przedefiniowanie umoliwia dostarczenie wasnej obsugi z darzenia.
public boolean action(Event evt, Object arg)

Metoda action reaguje na akcj wykonan na sterowniku (kliknicie przycisku, wybranie polecenia menu, wybranie elementu listy, nacinicie klawisza Enter po zakoczeniu edycji klatki tekstowej, itp.), w tym na akcj wykonan za pomoc myszki i klawiatury.
public public public public public public boolean boolean boolean boolean boolean boolean mouseDown (Event mouseUp (Event mouseMove (Event mouseDrag (Event mouseEnter(Event mouseExit (Event evt, evt, evt, evt, evt, evt, int int int int int int x, x, x, x, x, x, int int int int int int y) y) y) y) y) y)

Metody reaguj na akcj wykonan za pomoc myszki. Wykonanie kliknicia jest rozbite na dwie podakcje: nacinicie przycisku myszki (mouseDown) oraz zwolnienie go ( mouseUp). Ponadto umoliwiono obsug przesuwania i przecigania kursora myszki (mouseMove, mouseDrag) oraz obsug przemieszczenia kursora myszki do wntrza i na zewntrz obszaru sterownika (mouseEnter, mouseExit).
public boolean keyDown(Event evt, int key) public boolean keyUp (Event evt, int key)

Metody reaguj na nacinicie klawisza ( keyDown) oraz na zwolnienie go ( keyUp).


public boolean gotFocus (Event evt, Object arg) public boolean lostFocus(Event evt, Object arg)

Metody reaguj na otrzymanie/utrat wyrnienia.


public void requestFocus()

Metoda przyznaje sterownikowi wyrnienie. Nastpujcy program, pokazany podczas wykonywania na ekranie Wywietlanie znakw, wykrela w punkcie kliknicia ostatni znak wprowadzony z klawiatury. 91

Ekran Wywietlanie znakw


### drawkey.gif import java.io.IOException; import java.applet.*; import java.awt.*; public class Master extends Frame { Font font; String chr = " "; static Frame frame; Master() { super("PressKey & Click"); font = new Font("TimesRoman", Font.BOLD, 24); } public static void main(String args[]) throws IOException { frame = new Master(); frame.resize(160, 100); frame.show(); System.in.read(); System.exit(0); } public boolean keyUp(Event evt, int key) { chr = String.valueOf((char)key); return true; } public boolean mouseUp(Event evt, int x, int y) { Graphics gDC = getGraphics(); gDC.setFont(font); gDC.drawString(chr, x, y); return true; } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { hide(); // ukrycie ramki dispose(); // zniszczenie ramki return true; } else return super.handleEvent(evt); } }

Zajcie zdarzenia zewntrznego powoduje wywoanie podanej metody handleEvent przedefiniowujcej metod domnieman. W metodzie przedefiniowujcej rozpoznaje si tylko zdarzenie WINDOW_DESTROY generowane przez System w chwili rcznego zamknicia ramki utworzonej przez aplikacj. Pozostae zdarzenia s obsugiwane przez predefiniowana metod handleEvent wywoywan w instrukcji
return super.handleEvent(evt);

Metody keyUp i mouseUp s wywoywane przez t wanie metod handleEvent.

_________________________________________________________________________________________

Odtwarzanie pulpitu
Podczas programowania w rodowisku graficznym naley tak definiowa metod paint, aby po kadym wywoaniu jej przez System, nastpio pene odtworzenie obsugiwanego przez ni pulpitu. Nastpujcy program waciwie dostosowano do warunkw obsugiwania zdarze w dynamicznym i wielookienkowym rodowisku graficznym. 92

import import import import

java.io.IOException; java.applet.*; java.awt.*; java.util.*;

public class Master extends Frame { Font font; String chr = " "; Vector chars = new Vector(); static Frame frame; Master() { super("PressKey & Click"); font = new Font("TimesRoman", Font.BOLD, 24); } public static void main(String args[]) throws IOException { frame = new Master(); frame.resize(160, 100); frame.show(); System.in.read(); System.exit(0); } public boolean keyUp(Event evt, int key) { chr = String.valueOf((char)key); return true; } public boolean mouseUp(Event evt, int x, int y) { Graphics gDC = getGraphics(); gDC.setFont(font); gDC.drawString(chr, x, y); Item item = new Item(chr, x, y); chars.addElement(item); return true; } public void paint(Graphics gDC) { Font oldFont = gDC.getFont(); gDC.setFont(font); Enumeration charSet = chars.elements(); while(charSet.hasMoreElements()) { Object item = charSet.nextElement(); ((Item)item).draw(gDC); } gDC.setFont(oldFont); } } class Item { private String chr; private int x, y; public Item(String chr, int x, int y) { this.chr = chr; this.x = x; this.y = y; } public void draw(Graphics gDC) { gDC.drawString(chr, x, y); } }

W programie uyto predefiniowanej klasy Vector implementujc kolekcj tablicow o nieograniczonej liczbie elementw oraz interfejsu Enumeration definiujcym metody do iterowania kolekcji. Zgodnie z zasadami programowania obiektowego, kady element przewidziany do wywietlenia jest odrbnym obiektem ( tu klasy Item). 93

W klasie Item zdefiniowano nie tylko pola, ale rwnie metod do wykrelania obiektu. Rezultatem metody elements wywoanej w instrukcji
Enumeration charSet = chars.elements();

jest odnonik do iteratora, ktrego klasa zawiera metody hasMoreElements i nextElement. Umoliwiaj one dokonanie przegldu wszystkich elementw wstawionych do kolekcji chars.

94

Cz VI

Programowanie wspbiene

Istota programowania wspbienego polega na wykorzystaniu moliwoci jednoczesnego wykonania wsppracujcych i komunikujcych si ze sob procesw. W obrbie ustalonego programu takimi procesami s wtki. Wtkiem jest sekwencyjny przepyw sterowania przez kod wynikowy programu. Program jest napisany wielowtkowo, jeli podczas wykonywania go w rodowisku wieloprocesorowym mona stwierdzi, e s takie przedziay czasu, kiedy w co najmniej dwch procesorach wystpuje wspbieny (tj. rwnoczesny) przepyw sterowania przez kod wynikowy programu. W komputerach jednoprocesorowych, wspbieno wtkw jest tylko emulowana, a w kadej chwili przepyw sterowania odbywa si w tylko jednym wtku. Ale nawet w takim rodowisku, program wielowtkowy powinien by napisany tak, jakby mia by wykonany przez wiele procesorw. Najprostszym sposobem utworzenia programu wielowtkowego jest utworzenie obiektu klasy Thread, przekazanie mu odnonika do obiektu klasy zawierajcej metod run, a nastpnie wykonanie na rzecz pierwszego z tych obiektw metody start. Spowoduje to dla danego wtku aktywowanie metody run. Po jej zakoczeniu wtek przestanie istnie. Nastpujcy program, pokazany podczas wykonywania na ekranie Pulsujce okrgi, ilustruje zasad programowania wielowtkowego. Tworzy on okna, ktre s obsugiwane przez niezalene wtki. Ekran Pulsujce okrgi
### pulsars.gif import java.io.IOException; import java.awt.*; public class Master extends Frame implements Runnable { static final int count = 5; Thread thread; Master(int frameNo) { super("Frame #" + frameNo); resize(160, 100); show(); thread = new Thread(this); // utworzenie obiektu thread.start(); // utworzenie wtku } public static void main(String args[]) throws IOException { Frame frame[] = new Frame[count]; for(int i = 0; i < count ; i++) frame[i] = new Master(i); System.in.read(); System.exit(0); } public void run() { int xC = size/2, yC = xC; Graphics gDC = getGraphics(); while(true) { for(int i = 0; i < 70 ; i++) gDC.drawOval(0, 0, i, i); repaint(); } } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { hide(); // ukrycie okna dispose(); // zniszczenie okna thread.stop(); // zniszczenie wtku return true; } else return super.handleEvent(evt); } }

95

Utworzono count niezalenych wtkw, z ktrych kady posuguje si odrbnym oknem. Kod wtkw jest wsplny i okrelony przez metod run. Zamknicie okna powoduje zniszczenie posugujcego si nim wtku.

_________________________________________________________________________________________

Stany wtkw
Kady wtek wymaga istnienia kontrolujcego go obiektu klasy Thread. Wykonanie na rzecz obiektu kontrolujcego metody start powoduje utworzenie wtku, a wykonanie metody stop jego zniszczenie. W okresie midzy utworzeniem i zniszczeniem wtek istnieje, ale nie musi by czynny. Istniejcy wtek wykonuje si, pi, jest zawieszony albo czeka. O przebiegu wykonania wtku decyduje metoda run wywoana niejawnie przez System tu po utworzeniu wtku. Metoda run naley do klasy implementujcej interfejs Runnable. Miejsce jej wystpienia jest okrelone podczas tworzenia obiektu kontrolujcego wtek. Zakoczenie wykonywania metody run powoduje zniszczenie wtku.
public Thread(Runnable runClass)

Argument konstruktora identyfikuje obiekt klasy zawierajcej definicj metody run.


public void start() throws IllegalThreadStateException

Wywoanie metody powoduje utworzenie wtku.


public void stop()

Wywoanie metody powoduje zniszczenie wtku.


public static void sleep(long millis)

Wywoanie metody powoduje upienie wtku na podany okres czasu, wyraony w milisekundach.
public void suspend()

Wywoanie metody powoduje zawieszenie wtku.


public void resume()

Wywoanie metody powoduje odwieszenie wtku.


public void wait() throws InterruptedException, IllegalMonitorStateException

Wywoanie metody powoduje wstrzymanie wykonywania wtku z jego wasnej inicjatywy.


public void notify() throws IllegalMonitorStateException

Wywoanie metody powoduje uwolnienie jednego dobrowolnie wstrzymanego wtku.


public static void yield()

Wywoanie metody powoduje podzielenie si przez wtek dostpem do procesora. Po wywoaniu tej metody zostanie podjte wykonywanie innego wtku (o ile taki istnieje). Nie wyklucza to jednak zagodzenia wtku jeli jest ich wicej ni dwa.
public void join() throws InterruptedException

Wywoanie metody powoduje powstrzymanie wykonywania wtku a do zniszczenia go przez inny wtek.
public boolean isAlive()

Wywoanie metody umoliwia stwierdzenie czy wtek istnieje, to jest czy na rzecz obiektu kontrolujcego wtek wywoano ju metod start, ale nie wywoano jeszcze metody stop.

_________________________________________________________________________________________

Priorytety
Z kadym wtkiem jest zwizany priorytet, okrelajcy jego rang wrd innych wtkw. Priorytet jest liczb z przedziau 1..10. Jeli nie poda si go jawnie, to nowy wtek przejmie priorytet wtku ktry go utworzy.

96

Jako zasad przyjmuje si, e wtek o wyszym priorytecie uzyskuje wikszy przydzia procesora ni wtek o niszym priorytecie. Nie oznacza to jednak, e jeli s wykonywane wtki o rnych priorytetach, to ten o najwyszym zmonopolizuje procesor (chocia moe si tak sta!). Uwaga: Poleganie na priorytetach wtkw nie daje gwarancji co do kolejnoci ich wykonania i dlatego musi by uznane za przejaw zego stylu sterowania wykonaniem wtkw.

_________________________________________________________________________________________

Wtek gwny
W chwili rozpoczcia wykonywania programu istnieje tylko wtek gwny nalecy do grupy wtkw main. Wtek ten oraz kady inny, moe tworzy inne wtki. Kady wtek moe by uczyniony demonem. Wykonywanie programu koczy si bezporednio po tym, gdy zakoczy si wykonywanie ostatniego wtku, ktry nie jest demonem. Przykad Wtek gwny
import java.io.IOException; public class Master { public static void main(String args[]) throws IOException { Thread thread = Thread.currentThread(); System.out.println(thread); System.in.read(); } }

Wykonanie programu powoduje wyprowadzenie napisu


Thread[main,5,main]

_________________________________________________________________________________________

Tworzenie wtkw
W celu utworzenia wtku naley utworzy kontrolujcy go obiekt klasy Thread. Obiektowi temu naley przekaza odnonik do obiektu klasy implementujcej metod run interfejsu Runnable. Uwaga: Metod run mona zadeklarowa w tej samej klasie, do ktrej naley metoda tworzca wtek. Klasa tej metody musi implementowa interfejs Runnable.
import java.io.IOException; public class Master implements Runnable { public static void main(String args[]) throws IOException { System.out.println("Hello from MainThread"); Master myThis = new Master(); new Thread(myThis, "OtherThread").start(); System.in.read(); } public void run() { System.out.println("Hello from OtherThread"); } }

Podany program napisano wielowtkowo. Jest on wykonywany dwuwtkowo od chwili wywoania metody start
new Thread(this, "OtherThread").start();

97

to jest do chwili zakoczenia wykonywania funkcji main albo metody run (co zajdzie wczeniej). Wykonanie programu powoduje wyprowadzenie napisu
Hello from MainThread Hello from OtherThread

_________________________________________________________________________________________

Synchronizowanie wtkw
Jeli dwa, lub wicej, wtkw dzieli wsplny zasb (na przykad pami operacyjn), to szczegln trosk naley otoczy dostp do tego zasobu. Aby si przekona o koniecznoci synchronizowania dostpu, wystarczy rozpatrzy sytuacj, gdy rol wtkw peni dwaj kasjerzy, ktrzy maj nie-synchronizowany dostp do wsplnej bazy danych. Jeli na wsplnym koncie dwch osb jest na przykad $100, a kada z nich wpaca w osobnym okienku $20, to moe zaistnie nastpujca sytuacja Pierwszy kasjer sprawdza konto i odnotowuje jego stan ($100), ale co odrywa go do telefonu. Drugi kasjer sprawdza konto, odnotowuje jego stan ($100), dodaje $20 i aktualizuje konto (do $120). Pierwszy kasjer koczy rozmow, dodaje $20 do odnotowanej sumy i aktualizuje baz (do $120). W nastpstwie nie-synchronizowanego dostpu do bazy danych, nastpuje zwikszenie konta nie o $40, ale o $20. Nastpujcy program ilustruje sposb rozwizania przedstawionego problemu. Dziki synchronizacji dostpu do bazy dataBase, funkcja updateSavings moe by w danej chwili wykonywana tylko przez co najwyej jeden wtek.
import java.io.IOException; class Savings { private float savings; // ... void add(float amount) { savings += amount; } } class Transaction { int account; float amount; Transaction(int account, int amount) { // ... } // ... } public class Master { static float savingsData[] = { 100, 500, 300, 400, 200 }; static Savings dataBase[] = new Savings[savingsData.length]; static int noOfTellers = 2; public static void main(String args[]) throws IOException, InterruptedException { loadDataBase(dataBase, savingsData); Transaction setOne[] = { new Transaction(2, 10), new Transaction(4, 20) }, setTwo[] = { new Transaction(0, 30), new Transaction(2, 10)

98

}; // // // // // // =================== 100 500 300 400 200 10 20 30 10 =================== 130 500 320 400 220 Baza danych John Bill results

Teller john = new Teller("John", setOne, dataBase), bill = new Teller("Bill", setTwo, dataBase); Thread tellerOne = new Thread(john), tellerTwo = new Thread(bill); showDataBase(dataBase); tellerOne.start(); tellerTwo.start(); // ... Thread.currentThread().sleep(1000); // ... showDataBase(dataBase); System.in.read(); } // ... static void loadDataBase(Savings dataBase[], float savings[]) { // ... } static void showDataBase(Savings dataBase[]) { // ... } } class Teller implements Runnable { private String name; private Transaction set[]; private Savings dataBase[]; Teller(String name, Transaction set[], Savings dataBase[]) { this.name = name; this.set = set; this.dataBase = dataBase; } private void updateSavings(int i) { int account = set[i].account; float amount = set[i].amount; System.out.println(name + " " + account + " " + amount); dataBase[account].add(amount); } public void run() { for(int i = 0; i < set.length ; i++) synchronized(dataBase) updateSavings(i); Master.setDone(); } }

Podany program wyprowadza napis pokazany w tabeli Transakcje. Kolejno wierszy rodkowej czci napisu moe si zmienia od wykonania do wykonania. Uoglnienie programu na dowoln liczb kasjerw i transakcji jest trywialne. Tabela Transakcje
### Account Account Account Account #1 #1 #2 #3 $100 $500 $300 $400

99

Account #4 $200 John Bill John Bill 2 0 4 2 10 30 20 10 #1 #1 #2 #3 #4 $130 $500 $320 $400 $220

Account Account Account Account Account ###

_________________________________________________________________________________________

Instrukcja synchronizujca
Do synchronizowania wtkw suy instrukcja
synchronized(exp)Block

w ktrej exp jest nazw odnonika, a Block jest instrukcj grupujc. Wykonanie instrukcji synchronizujcej powoduje przydzielenie wtkowi bloku sekcji krytycznej zwizanej z obiektem identyfikowanym przez odnonik, a po wykonani u instrukcji bloku, zwolnienie sekcji. Uwaga: Jeli podczas wykonywania sekcji krytycznej zwizanej z pewnym obiektem, jakikolwiek inny wtek podejmie prb wykonania tej samej sekcji krytycznej zwizanej z tym samym obiektem, to jego wykonanie wtku zostanie zablokowane do chwili zwolnienia sekcji. W nastpujcej funkcji, wykonanie sekcji krytycznej wyznaczonej przez instrukcj synchronized, moe by w danej chwili, na rzecz tego samego obiektu point, realizowane tylko przez co najwyej jeden wtek. Dziki temu wywoanie metody incPoint powoduje zwikszenie obu pl (x, y) o t sam warto.
class Master { // ... public Point incPoint(Point point) { synchronized(point) { point.incXY(); return point; } } } class Point { int x, y; void incXY() { this.x = x + 1; this.y = y + 1; } // ... }

Uwaga: Gdyby zrezygnowano z uycia instrukcji synchronized, a metod incPoint wywoano z dwch rnych wtkw, to mogoby si zdarzy, e po takich operacjach wsprzdne x i y punktu nie byyby rwne.

_________________________________________________________________________________________

Procedury synchronizowane
Procedur synchronizowan jest procedura zadeklarowana ze specyfikatorem synchronized.
class Counter { private int counter = 0;

100

public synchronized void Counter() { counter += 1; } }

Uwaga: Semantyka procedur synchronizowanych zostanie wyjaniona przez powoanie si na instrukcj synchronized

Metody synchronizowane
Wywoanie w instrukcji
ref.met(arg, arg, ... , arg);

metody synchronizowanej met, na rzecz obiektu identyfikowanego przez odnonik ref jest rwnowane wywoaniu
synchronized(ref) { ref.met2(arg, arg, ... , arg); }

identycznej z ni metody niesynchronizowanej met2.

Funkcje synchronizowane
Wywoanie w instrukcji
Class.fun(arg, arg, ... , arg);

funkcji synchronizowanej fun nalecej do klasy Class jest rwnowane wywoaniu


try { synchronized(Class.forName(Class)) { Class.fun2(arg, arg, ... , arg); } } catch(ClassNotFoundException e) { }

identycznej z ni funkcji niesynchronizowanej fun2.

_________________________________________________________________________________________

Monitor
Z kadym obiektem klasy jest skojarzony monitor. Jeli metoda synchronizowana klasy zostanie wywoana na rzecz obiektu, to wywoujcy j wtek zajmie monitor tego obiektu. Do czasu zwolnienia monitora zostanie zablokowane wykonanie kadego innego wtku, ktry podejmie prb wywoania (na rzecz tego samego obiektu), dowolnej funkcji sychronizowanej danej klasy. Wtek zajmujcy monitor moe posugiwa si metodami wait i notify. Biorc pod uwag pojcie monitora, ich opisy przybieraj nastpujc posta:
public void wait() throws InterruptedException, IllegalMonitorStateException

Wywoanie metody powoduje zwolnienie monitora przez wtek i dobrowolne wstrzymanie wykonywania wtku. Umoliwi to innemu wtkowi ubieganie si o przydzielenie monitora.
public void notify() throws IllegalMonitorStateException

Wywoanie metody powoduje uwolnienie jednego dobrowolnie wstrzymanego wtku. Umoliwi to uwolnionemu wtkowi ubieganie si o zajcie monitora, ale nie wczeniej ni monitor zostanie zwolniony przez wtek wywoujcy metod notify. 101

Produkcja i konsumpcja
Nastpujcy program ilustruje uycie monitora do oprogramowana klasycznego problemu Producent-Konsument. Producent wkada liczby do pudeka, a konsument je wyjmuje. Jeli pudeko jest puste, to czeka konsument, a jeli jest pene, to czeka producent. Przykad Produkcja-Konsumpcja
import java.io.IOException; import java.io.*; public class Master { static Box box = new Box(); public static void main(String args[]) throws IOException { new Producer(box); new Consumer(box); } } class Producer implements Runnable { Box box; Producer(Box box) { this.box = box; new Thread(this).start(); } public void run() { for(int number = 0; number < 5 ; number++) box.putInto(number+1); box.setDone(); } } class Consumer implements Runnable { Box box; Consumer(Box box) { this.box = box; new Thread(this).start(); } public void run() { int gotFrom; while(true) try { gotFrom = box.getFrom(); } catch(IOException e) { } } } class Box { int contents; boolean boxEmpty = true; static boolean producerDone = false; public Box() { } synchronized void setDone() { producerDone = true; } synchronized int getFrom() { if(boxEmpty) { if(producerDone) {

// flaga koca

102

System.in.read(); System.exit(0); } else try { wait(); } catch(InterruptedException e) { } } int number = contents; System.out.println("Number " + number + " from Box"); boxEmpty = true; notify(); return number; } synchronized void putInto(int number) { if(!boxEmpty) try { wait(); } catch(InterruptedException e) { } contents = number; System.out.println("Number " + number + " to Box"); boxEmpty = false; notify(); } }

Producent i konsument operuj na wsplnym zasobie jakim jest pudeko box. Wykonanie programu powoduje wyprowadzenie napisu
Number Number Number Number Number 1 1 2 2 3 to Box from Box to Box from Box to Box

itd. Po wstawieniu do programu bardziej szczegowych polece informujcych o przebiegu wydarze mona otrzyma sekwencj napisw pokazan w tabeli Produkcja-konsumpcja. Tabela Produkcja-konsumpcja
### koniec wykonania funkcji main startuje producent producent wywouje putInto(1) producent wstawia 1 w pudeka producent wywouje putInto(2) startuje konsument konsument wywouje getFrom konsument dostaje 1 z pudeka konsument wywouje getFrom producent wstawia 2 do pudeka konsument dostaje 2 z pudeka producent wywouje putInto(3) konsument wywouje getFrom producent wstawia 3 do pudeka producent wywouje putInto(4) konsument dostaje 3 z pudeka producent wstawia 4 do pudeka konsument wywouje getFrom producent wywouje putInto(5) konsument dostaje 4 z pudeka producent wstawia 5 do pudeka konsument wywouje getFrom producent koczy wykonywanie konsument dostaje 5 z pudeka konsument wywouje getFrom ale wykonanie trwa zaczyna dziaa

dopiero teraz

ustawia flag koca

103

konsument koczy wykonywanie ###

po zbadaniu flagi

_________________________________________________________________________________________

Impas
O ile synchronizacja nie jest zaprojektowana prawidowo, moe powsta impas. Wystpuje on wwczas, gdy w zestawie wspdziaajcych wtkw kady jest zawieszony albo dobrowolnie wstrzymany, ale nie istnieje moliwo odwieszenia ani uwolnienia przynajmniej jednego wtku. Nastpujcy program monitoruje prac dwch osb. Kada z nich informuje o postpach swoich i konkurenta.
import java.io.IOException; public class Master { static Worker tom, bob; public static void main(String args[]) throws IOException { tom = new Worker("Tom"); bob = new Worker("Bob"); new Thread(tom.setOther(bob)).start(); new Thread(bob.setOther(tom)).start(); System.in.read(); } static synchronized void sendMessage(String string) { System.out.println(string); } } class Worker implements Runnable { private long counter = 0; String name; Worker other; Worker(String name) { this.name = name; } Worker setOther(Worker other) { this.other = other; return this; } synchronized void showStatus() { Master.sendMessage(name + " " + counter + ", other: " + other.peep()); } synchronized long peep() { return counter; } public void run() { while(true) { counter++; // wykonanie pracy showStatus(); // komunikat } } }

Podczas wykonywania programu moe (ale nie musi!) doj do impasu. Dojdzie do niego na przykad przy nastpujcym splocie wydarze: 1. 2. Wtek Tom wywouje metod showStatus. Poniewa showStatus jest metod synchronizowan, wic wtkowi Tom przydziela si monitor zwizany ze zmienn Master.tom. 104

Niech w tym miejscu zostanie przerwane wykonywanie wtku Tom. 3. 4. 5. 6. Zaczyna si wykonywa wtek Bob i wywouje metod showStatus. Poniewa showStatus jest metod synchronizowan, wic wtkowi Bob przydziela si monitor zwizany ze zmienn Master.bob. Metoda showStatus wywouje metod synchronizowan peep. Poniewa peep jest metod synchronizowan, wic wtek Bob spodziewa si przydzielenia monitora zwizanego ze zmienn Master.tom (zmienna other jest odnonikiem do tej wanie zmiennej). Monitor jest ju jednak przydzielony, wic wtek Bob zawiesza si, w oczekiwaniu na zwolnienie monitora. Niech w tym miejscu nastpi wznowienie wykonywania wtku Tom. 7. 8. 9. Wtek Tom wywouje metod peep. Poniewa peep jest metod synchronizowan, wic wtek Tom spodziewa si przydzielenia monitora zwizanego ze zmienn Master.bob (zmienna other jest odnonikiem do tej wanie zmiennej). Monitor jest ju jednak przydzielony, wic wtek Tom zawiesza si, w oczekiwaniu na zwolnienie monitora.

Wystpi impas. aden z rozpatrywanych wtkw nie wykonuje si. Zgodnie z oczekiwaniami, wykonanie programu w systemie Windows 95 do szybko doprowadzao do impasu. Niemal kade wykonanie dawao inn sekwencj wyjciow. Najkrtsz z uzyskanych, ale dusz od pustej (sic!), przytoczono w tabeli Wyniki przed impasem. Najbardziej interesujcy jest niej drugi wiersz, z ktrego wynika, e Tom wykona ju 2 operacje, podczas gdy informowa o wykonaniu tylko jednej! Tabela Wyniki przed impasem
### Tom Bob Tom Tom Tom Bob Tom ### 1, 1, 2, 3, 4, 2, 5, other: other: other: other: other: other: other: 0 2 1 1 1 4 3

105

Cz VII

Programowanie apletw

W odrnieniu od aplikacji, ktra jest programem samodzielnym, aplet jest programem wbudowanym w inn aplikacj (np. w przegldark Netscape). Aplikacja ta zapewnia wykonanie i wizualizacj apletu. Wraz z B-kodem apletu naley dostarczy przegldarce opis apletu. Opis jest zawarty w pliku z rozszerzeniem .html. Jego nazwa jest zazwyczaj identyczna z nazw pliku zawierajcego program rdowy apletu. Nastpujcy aplet, pokazany podczas wykonania na ekranie Wachlarz, wywietla obracajcy si odcinek. Ekran Wachlarz
### fan.gif

Przykad Wachlarz
<applet code=Master.class width=0 height=0> </applet> =========================================== import java.applet.*; import java.awt.*; public class Master extends Applet implements Runnable { private boolean stopped = false; private final int rad = 50; private Graphics gDC; private Thread thread = new Thread(this); private int size, xC, yC; public void init() { gDC = getGraphics(); size = 2*rad + 10; xC = yC = size/2; resize(size, size); thread.start(); } public boolean mouseUp(Event evt, int x, int y) { stopped = !stopped; return true; } public void run() { double angle = 0; int i = 0; while(!stopped) { if(i++ == 40) { repaint(); i = 0; angle = 0; } int x = (int)(rad * Math.cos(angle)), y = (int)(rad * Math.sin(angle)); gDC.drawLine(xC + x, yC - y, yC - x, yC + y); try { Thread.currentThread().sleep(100); } catch(InterruptedException e) { thread.stop(); } angle = angle + Math.PI / 36; } } }

Rozmiary apletu okrelono nie w jego opisie, ale w w metodzie init programu. Kliknicie lewym przyciskiem myszki powoduje zakoczenie wykrelania. 106

_________________________________________________________________________________________

Opis
Z kadym apletem przewidzianym do wykonania w przegldarce musi by zwizany dokument HTML zawierajcy opis apletu. Opis apletu musi zawiera parametry code, width i height. Argumenty zawarte we frazach param s dostpne w programie za pomoc metody getParameter. Skadni opisu apletu zamieszczono w tabeli Opis apletu. Wymieniony w niej TekstZastpczy jest wywietlany przez przegldark, ktra nie rozpoznaje opisu apletu. Tabela Opis apletu
### <applet codebase = cieka code = Plik alt = Tekst name = Oznaczenie width = Szeroko height = Wysoko align = Wyrwnanie vspace = Uskok hspace = Wcicie > <param name = Nazwa value = Warto > <param name = Nazwa value = Warto > ... j.w. TekstZastpczy </applet> ### codebase = cieka

Parametr okrela ciek do katalogu zawierajcego plik z B-kodem apletu. cieka wzgldna, np. subdir\code jest odnoszona do katalogu, w ktrym znajduje si opis apletu. ciek domyln jest . (kropka).
code = Plik

Parametr podaje nazw pliku z rozszerzeniem .class, zawierajcego B-kod apletu. Przyjmuje si, e nazw cieki do pliku okrela parametr codebase.
alt = Tekst

Parametr podaje tekst, ktry zostanie wywietlony zamiast apletu przez tak przegldark, ktra rozpoznaje opis apletu, ale nie moe wywietli apletu.
name = Oznaczenie

Parametr podaje nazw apletu, odrniajc go od innych apletw tej samej strony WWW. W celu odwoania si do apletu przez nazw naley w programie uy instrukcji podobnej do
Applet myApplet = getAppletContext().getApplet(Oznaczenie); width = Szeroko

Parametr podaje pocztkow szeroko apletu na stronie WWW (wyraon w pikselach).


height = Wysoko

Parametr podaje pocztkow wysoko apletu na stronie WWW (wyraon w pikselach).


align = Wyrwnanie

Parametr podaje sposb usytuowania apletu na stronie WWW. Dopuszczalnymi wartociami Wyrwnania s: left, right, top, texttop, middle, absmiddle, baseline, bottom, absbottom.
vspace = Uskok

Parametr podaje pionowy odstp powyej i poniej apletu (wyraony w pikselach).


hspace = Wcicie

Parametr podaje poziomy odstp przed i po aplecie (wyraony w pikselach).


<param name = Nazwa value = Warto >

107

Parametr umoliwia okrelenie parametru apletu. Parametrw param moe by w opisie apletu dowolnie wiele. Kady z nich okrela Nazw i Warto argumentu (mae i due litery s uznawana za rne). Wartoci, ktre zawieraj odstpy i znaki specjalne, naley uj w cudzysowy. W celu uycia w programie parametru apletu naley uy instrukcji
String Value = getParameter("Name");

a nastpnie dokona analizy i konwersji acucha Value, na przykad


int Fixed = Integer.parseInt(Value);

albo
double Real = Double.valueOf(Value).doubleValue();

Uwaga: Jeli oczekiwany argument nie istnieje, to metoda getParameter zwraca odniesienie puste (null). Nastpujcy aplet, pokazany podczas wykonania na ekranie Kolory, wywietla napis
Hello

czcionk o rozmiarze 48 punktw, w kolorze karmazynowym. Uwaga: Kolor karmazynowy ma skadniki RGB(255,0,255). Ekran Kolory
### colors.gif <applet codebase = d:\applets code = Master.class width = 300 height = 80> <param name = Size value = 48> <param name = Color value = "255,0,255"> </applet> ========================================= import java.applet.*; import java.awt.*; public class Master extends Applet { private static Color color; private static Font font; public void init() { String sizeString = getParameter("Size"); if(sizeString == null) throw new IllegalArgumentException("No Size"); int size; try { size = Integer.parseInt(sizeString); } catch(NumberFormatException e) { throw new IllegalArgumentException("Size"); } String colorString = getParameter("Color"); if(colorString == null) throw new IllegalArgumentException("No Color"); color = getColor(colorString); font = new Font("Courier", Font.ITALIC, size); } public void paint(Graphics gDC) { gDC.setColor(color); gDC.setFont(font); gDC.drawString("Hello", 100, 60); } Color getColor(String triplet)

108

{ String string = triplet + ",.", tmpString; int rgb[] = new int [3]; for(int i = 0; i < 3 ; i++) { int index = string.indexOf(","); if(index < 0) throw new IllegalArgumentException("Color"); tmpString = string.substring(0, index); try { rgb[i] = Integer.parseInt(tmpString); } catch(NumberFormatException e) { throw new IllegalArgumentException("Color"); } string = string.substring(index+1); } if(!string.equals(".")) throw new IllegalArgumentException("Color"); return new Color(rgb[0], rgb[1], rgb[2]); } }

Dokonano penej kontroli poprawnoci parametrw apletu. Zabieg taki jest kosztowny, ale mimo to zalecany.

_________________________________________________________________________________________

Wykonanie
W chwili rozpoznania opisu apletu, przegldarka tworzy obiekt klasy apletu, a nastpnie wywouje na jego rzecz metod init. Tu przed zniszczeniem obiektu jest wywoywana metoda destroy. W czasie istnienia obiektu s dodatkowo wywoywane metody start, stop, update i paint. Z dowolnej procedury apletu mog by ponadto wywoywane metody repaint, resize i reshape.
public void init()

Metoda init jest wywoywana jednokrotnie, tu po pierwszym zaadowaniu strony WWW zawierajcej aplet. Przejcie na inn stron WWW i powrt do strony zawierajcej aplet nie powoduje ponownego wywoania metody init.
public void start()

Metoda start jest wywoywana za kadym razem, gdy strona WWW zawierajca aplet staje si stron biec.
public void stop()

Metoda stop jest wywoywana za kadym razem gdy strona WWW zawierajca aplet przestaje by stron biec.
public void update(Graphics gDC)

Metoda update jest wywoywana za kadym razem, gdy zachodzi potrzeba wykrelenia apletu. Na przykad tu po wykonaniu metody start oraz po wywoaniu takich metod jak repaint i resize. Domniemana metoda update czyci pulpit apletu aktualnym kolorem ta, a nastpnie wywouje metod paint.
public void paint(Graphics gDC)

Wywoanie metody paint suy do wykrelenia apletu. Kady aplet, ktry trwale modyfikuje swj pulpit powinien dostarczy wasn definicj metody paint. Domniemana metoda paint nie robi nic. Kilka kolejnych wywoa metody paint moe by zastpione przez System tylko jednym jej wykonaniem.
public void repaint() public void repaint(long time) public void repaint(int x, int y, int width, int height)

Wywoanie metody repaint jest apelem, aby System w miar szybko, ale w wybranej przez siebie chwili, wywoa metod update (ktra z kolei wywoa paint). O ile nie przedefiniowano tych metod, doprowadzi to do wyczyszczenia i odtworzenia pulpitu. Metoda repaint moe by wywoana z argumentami okrelajcymi prostoktny obszar obcinania ograniczajcy obszar odtwarzania pulpitu. Jeli zostanie wywoana z argumentem time, a System nie zdoa uwzgldni apelu w podanym czasie, to apel ma by zignorowany.
public void resize(int width, int height)

Wywoanie metody resize powoduje zmian rozmiarw apletu. Bezporednio po uwzgldnieniu nowych rozmiarw, System wywouje metod repaint. 109

public void destroy()

Metoda destroy jest wywoywana jednokrotnie, tu przed jawnym zniszczeniem apletu (na przykad w chwili zamknicia przegldarki). Metoda destroy jest zazwyczaj wykorzystywana do zwolnienia zasobw przydzielonych apletowi. Nastpujcy aplet, pokazany podczas wykonania na ekranie Obsuga apletu, wywietla w odrbnym oknie informacje o wywoywanych zewntrznie metodach jego klasy. Ekran Obsuga apletu
### methods.gif <applet code=Master.class width=160 height=80> </applet> ============================================= import java.applet.*; import java.awt.*; public class Master extends Applet { Frame frame; int yPos = 20; Graphics gDC; public void init() { frame = new MyFrame("Msg"); frame.resize(100, 200); frame.show(); gDC = frame.getGraphics(); sendMsg("init"); } void sendMsg(String msg) { gDC.drawString(msg, 10, yPos); yPos = yPos + 20; } public void start() { sendMsg("start"); } public void stop() { sendMsg("stop"); } public void update(Graphics gDC) { sendMsg("update"); super.update(gDC); } public void paint(Graphics gDC) { gDC.drawString("Click me!", 10, 20); sendMsg("paint"); } public boolean mouseUp(Event evt, int x, int y) { sendMsg("mouseUp"); return true; } } class MyFrame extends Frame { MyFrame(String caption) { super(caption); } public void update(Graphics gDC) { } }

Gdyby instrukcj 110

frame = new MyFrame("Msg");

zastpiono instrukcj
frame = new Frame("Msg");

to po wywoaniu predefiniowanej metody update klasy Frame (co nastpioby po wykonaniu metody start), nastpioby wyczyszczenie napisu
init

ju wysanego do okna. Wynika std wniosek, e posugujc si odrbnymi oknami tworzonymi przez aplet, naley unika wykrelania w nich tekstw i grafiki podczas wykonywania metod init i start.

_________________________________________________________________________________________

Otoczenie
Kady aplet ma otoczenie, ktre moe rozpozna i z ktrym moe si komunikowa. Podstawowymi metodami do rozpoznania otoczenia apletu s getCodeBase i getDocumentBase. Wysyanie krtkich komunikatw do otoczenia odbywa si za pomoc metody showStatus.

Lokalizator
Lokalizowanie zasobw otoczenia odbywa si za pomoc lokalizatora zasobw (Uniform Resource Locator). W oglnym wypadku, parametrami lokalizatora s: nazwa protokou komunikacyjnego, najczciej HTTP (Hypertext Transfer Protocol), nazwa komputera-gospodarza (host), numer portu (dla HTTP zwyczajowo 80) oraz nazwa pliku. Informacje o lokalizatorze s przechowywane w obiekcie klasy URL (Uniform Resource Locator) inicjowanym na przykad za pomoc argumentu
http://www.microsoft.com:80/index.html

public URL getCodeBase()

Metoda dostarcza odnonik do obiektu klasy URL identyfikujcego katalog, w ktrym znajduje si B-kod apletu.
public URL getDocumentBase()

Metoda dostarcza odnonik do obiektu klasy URL identyfikujcego katalog, w ktrym znajduje si dokument HTML z opisem apletu.
public void showStatus(String msg)

Wywoanie metody powoduje wywietlenie komunikatu o stanie apletu. Uwaga: Ujawnienie okna konsoli w przegldarce Netscape wymaga wydania w niej polecenia Options/Show Java Console. Nastpujcy aplet, pokazany podczas wykonania na ekranie Pcherzyki, wywietla obraz zawarty w pliku. Plik znajduje si w tym samym katalogu co B-kod apletu. Ekran Pcherzyki
### bubbles.gif <applet code=Master.class width=160 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; import java.net.*; public

111

class Master extends Applet { Image myImage; public void init() { URL codeBase = getCodeBase(); myImage = getImage(codeBase, "Bubbles.gif"); } public void paint(Graphics gDC) { gDC.drawImage(myImage, 10, 10, this); } }

Wykonanie programu powoduje wywietlenie obrazu znajdujcego si w pliku Bubbles.gif.

_________________________________________________________________________________________

Grafika
Doczona do jzyka biblioteka AWT umoliwia wykrelanie podstawowych obiektw graficznych: tekstw, odcinkw, prostoktw, elips, okrgw, ukw i wieloktw. Wykrelanie odbywa si za pomoc metod klasy abstrakcyjnej Graphics.
public void drawString(String str, int x, int y)

Wykrelenie tekstu str w prostokcie, ktrego lewy-dolny naronik ma wsprzdne (x,y).


public void drawLine(xA, yA, xZ, yZ)

Wykrelenie odcinka czcego punkty o wsprzdnych (xA, yA) i (xZ, yZ).


public void drawRect(int x, int y, int w, int h)

Wykrelenie prostokta o wsprzdnych lewego -grnego wierzchoka (x,y) i rozmiarach w x h pikseli (w - szeroko, h wysoko).
public void drawOval(int x, int y, int w, int h)

Wykrelenie owalu (okrgu albo elipsy) wpisanego w niewidoczny prostokt, o wsprzdnych lewego -grnego wierzchoka (x,y) i rozmiarach w x h pikseli.
public void drawArc(int x, int y, int w, int h, int f, int t)

Wykrelenie uku wpisanego w niewidoczny prostokt, o wsprzdnych lewego -grnego wierzchoka (x,y) i rozmiarach w x h pikseli, od kta pocztkowego f do kta kocowego t.
public void drawPolygon(int x[], int y[], int n)

Wykrelenie linii amanej czcej n punktw o wsprzdnych (x[i], y[i]).


public void fillRect(int x, int y, int w, int h)

Wykrelenie wypenionego prostokta (por. drawRect).


public void fillOval(int x, int y, int w, int h)

Wykrelenie wypenionego owalu (por. drawOval).


public void fillPolygon(int x[], int y[], int n)

Wykrelenie wypenionego wielokta (por. drawPolygon).

Kontekst
Z kadym dajcym si wykreli komponentem jest zwizany kontekst graficzny. Informacje o kontekcie znajduj si w obiekcie wykrelacza. Odnonik do wykrelacza jest dostpny poprzez parametr metody paint. Mona go take otrzyma za pomoc metody getGraphics.
public Graphics getGraphics()

Metoda zwraca odnonik do wykrelacza zwizanego z komponentem, albo odniesienie null, jeli komponent nie moe pojawi si na ekranie. 112

Uwaga: Zaleca si, aby po umieszczeniu w wykrelaczu pewnej informacji (np. rodzaju czcionki albo koloru pira) przywrcono jego stan pierwotny. Dziki temu uniknie si kolizji wynikajcych z uycia tego samego wykrelacza przez rne komponenty. Na przykad
public void draw(Graphics gDC) { Font oldFont = gDC.getFont(); Color oldColor = gDC.getColor(); // ... Font font = new Font("TimesRoman", Font.BOLD, 80); gDC.setFont(font); gDC.setColor(Color.red); gDC.drawString("Hello", 10, 20); // ... gDC.setColor(oldColor); gDC.setFont(oldFont); }

Po zakoczeniu wykonywania metody draw, wykrelacz identyfikowany przez odnonik gDC znajduje si w takim samym stanie jak w chwili rozpoczcia wykonywania tej metody. Nastpujcy aplet, pokazany podczas wykonania na ekranie Konteksty graficzne, ilustruje zasady posugiwania si wykrelaczami. Ekran Konteksty graficzne
### getgdc.gif <applet code=Master.class width=160 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void paint(Graphics gDC) { gDC.drawString("Press to draw a Circle", 20, 20); } public boolean mouseDown(Event evt, int x, int y) { Graphics gDC = getGraphics(); gDC.drawOval(x-10, y-10, 20, 20); // wykrelenie return true; } public boolean mouseUp(Event evt, int x, int y) { Graphics gDC = getGraphics(); update(gDC); // wyczyszczenie return true; } }

Wywoanie metody getGraphics powoduje dostarczenie odnonika do wykrelacza zwizanego z pulpitem apletu. Nacinicie klawisza myszki powoduje wykrelenie okrgu o rodku w punkcie, w ktrym znajduje si kursor, a zwolnienie przycisku powoduje usunicie okrgu z ekranu.

Wsprzdne
Ukad wsprzdnych pojemnika (np. ramki apletu) ma punkt pocztkowy w lewym-grnym naroniku. Odcite (x) zwikszaj si prawo, a rzdne (y) do dou. Podczas wykrelania obiektu podaje si lew-grn wsprzdn oraz rozmiary: poziomy i pionowy.
public void paint(Graphics gDC) { gDC.drawRect(10, 20, 100, 200); // (x, y, w, h)

113

Wyjtek od tej zasady dotyczy wykrelania napisw. W tym wypadku podaje si wsprzdne lewego-dolnego naronika niewidocznej linii na ktrej spoczywa napis. Nastpujcy aplet, pokazany podczas wykonania na ekranie Wsprzdne komponentw, ilustruje zasad okrelania wsprzdnych napisw i grafiki. Ekran Wsprzdne komponentw
### over.gif <applet code=Master width=160 height=60> </applet> ========================================= import java.applet.*; import java.awt.*; public class Master extends Applet { public void paint(Graphics gDC) { gDC.drawString("Text over rectangle", 10, 20); gDC.drawRect(10, 20, 80, 5); } }

Mimo i w obu przypadkach podano te same wsprzdne naronika, niewidoczny prostokt, w ktry wpisano napis nie pokrywa si z prostoktem wykrelonym jawnie.

Pulpit
Ta cz obszaru pojemnika, na ktrej odbywa si wykrelanie grafiki ( odcinkw, owali, prostoktw, itp.) jest jego pulpitem. Podczas wstawiania komponentw do pojemnika uywa si wsprzdnych pojemnika, ale podczas wykrelania grafiki oraz obsugiwania zdarze zwizanych z operacjami wykonywanymi za pomoc myszki uywa si wsprzdnych pulpitu.

Wcicia
Obszar pulpitu jest wcity wzgldem obszaru pojemnika. Rozmiary pojemnika mona okreli za pomoc metody size, a rozmiary wci za pomoc metody insets. Uwaga: Domniemane wcicia dla apletu maj warto 0. A zatem obszar i pulpit apletu pokrywaj si. W systemie Windows 95 domniemane wcicia dla ramki maj wartoci 4, 23, 4, 4.
public Dimension size()

Metoda zwraca odnonik do obiektu, ktrego pola width i height okrelaj poziomy i pionowy rozmiar obszaru pojemnika. public Insets insets() Metoda zwraca odnonik do obiektu, ktrego pola left (lewe), top (grne), right (prawe) i bottom (dolne) okrelaj wcicia krawdzi pulpitu wzgldem krawdzi obszaru pojemnika. Nastpujcy aplet, pokazany podczas wykonania na ekranie Pulpit apletu i ramki, ilustruje zasady uwzgldniania wci. Ekran Pulpit apletu i ramki
### insets.gif <applet code=Master width=160 height=100> </applet> ========================================= import java.applet.*; import java.awt.*; public

114

class Master extends Applet { Frame frame; Button hello, world; int w, h; public void init() { setLayout(null); add(hello = new Button("Hello")); hello.reshape(1, 1, 60, 40); frame = new MyFrame("Frame View"); Insets ins = frame.insets(); frame.add(world = new Button("World")); int l = ins.left, // 4 t = ins.top, // 23 r = ins.left, // 4 b = ins.bottom; // 4 world.reshape(l+1, t+1, 60, 40); Dimension size = size(); // 160 x 100 int w = size.width + (l + r), h = size.height + (t + b); frame.resize(w, h); } public void paint(Graphics gDC) { Dimension dim = size(); Insets ins = insets(); int w = dim.width - (ins.left + ins.right), h = dim.height - (ins.top + ins.bottom); gDC.drawRect(0, 0, w-1, h-1); } public boolean mouseUp(Event evt, int x, int y) { Dimension dim = size(); Insets ins = insets(); int w = dim.width, h = dim.height; Graphics gDC = getGraphics(); int xC = w/2, yC = h/2; gDC.drawLine(x, y, xC, yC); return true; } } class MyFrame extends Frame { MyFrame(String caption) { super(caption); show(); } public void paint(Graphics gDC) { Dimension dim = size(); Insets ins = insets(); int w = dim.width - (ins.left + ins.right), h = dim.height - (ins.top + ins.bottom); gDC.drawRect(0, 0, w-1, h-1); } public boolean mouseUp(Event evt, int x, int y) { Dimension dim = size(); Insets ins = insets(); int w = dim.width - (ins.left + ins.right), h = dim.height - (ins.top + ins.bottom); Graphics gDC = getGraphics(); int xC = w/2, yC = h/2; gDC.drawLine(x, y, xC, yC); return true; } }

115

Program napisano w taki sposb, aby rozmiar pulpitu ramki by identyczny z rozmiarem pulpitu apletu. W celu uwidocznienia pulpitw wykrelono na nich prostokty o maksymalnych rozmiarach. Jak wynika z rozpatrzenia kodu programu, umieszczenie przycisku na pulpicie ramki oraz wykrelenie odcinka czcego punkt kliknicia ze rodkiem ramki wymaga uwzgldnienia wci. Problemy te nie wystpuj dla apletw.

Obcinanie
Jeli wykres nie mieci si na pulpicie apletu, to jest obcinany. Dziki temu nic nie stoi na przeszkodzie "wykrelania" obiektw, ktre nie mieszcz si na pulpicie. Domylnym obszarem obcinania jest pulpit apletu. Za pomoc metody clipRect wywoanej na rzecz wykrelacza, mona jako obszar obcinania okreli dowolny inny prostokt.
public void clipRect(int x, int, y, int width, int height)

Wywoanie metody powoduje okrelenie jako obszaru obcinania, prostokta o wsprzdnych naronika ( x,y) i rozmiarach w x h.. W nastpujcym programie, pokazanym podczas wykonywania na ekranie Obszar obcinania, wykrelono prostokt, a nastpnie zajty przeze obszar zdefiniowano jako obszar obcinania. Dlatego wykres jednego z okrgw jest obcity do wybranego prostokta. Ekran Obszar obcinania
### clip.gif

Przykad Obcinanie
<applet code=Master width=160 height=80> </applet> ========================================= import java.applet.*; import java.awt.*; public class Master extends Applet { public void paint(Graphics gDC) { gDC.drawRect(25, 25, 50, 50); gDC.clipRect(25, 25, 50, 50); gDC.drawOval(0, 25, 50, 50); Dimension size = this.size(); int w = size.width, h = size.height; gDC.clipRect(0, 0, w, h); gDC.drawOval(50, 25, 50, 50); } }

Przez ustawienie jako obszaru obcinania caego pulpitu apletu, przywrcono obcinanie domylne.

Czcionki
Czcionk charakteryzuje rozmiar, krj i styl. Na przykad tytu niniejszego podrozdziau jest napisany 14-punktow czcionk TimesRoman, w stylu Bold. Majc na wzgldzie przenono wygldu czcionki zaleca si posugiwa tylko czcionkami o nazwach podanych w tabeli Czcionki (dla porwnania podano ich odpowiedniki w systemie Windows). Uwaga: Czcionka domylna ma rozmiar 12 punktw i styl zwyky. Tabela Czcionki
### Java TimesRoman Helvetica Windows Times New Roman Arial

116

Courier Dialog Symbols ###

Courier New MS Sans Serif WingDing

Do zapisania stylu mona posuy si symbolami podanymi w tabeli Style czcionki. Tabela Style czcionki
### Styl zwyky kursywa pogrubiony pogrubiona kursywa ### Symbol Font.PLAIN Font.ITALIC Font.BOLD Font.BOLD + Font.ITALIC

Czcionka jest reprezentowana przez obiekt klasy Font. W wywoaniu jej konstruktora okrela si krj, styl i rozmiar czcionki.
public Font(String name, int style, int size)

Konstruktor tworzy obiekt czcionki o podanym kroju, stylu i rozmiarze. Jeli w danym Systemie taka czcionka nie istnieje, to zostanie utworzona czcionka maksymalnie zbliona do wymaganej. Nastpujcy program, pokazany podczas wykonania na ekranie Kroje i style, wywietla zestaw 12 pt czcionek o rnych krojach i stylach. Ekran Kroje i style
### typeface.gif <applet code=Master.class width=160 height=200> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { String string; String typeFace[] = { "TimesRoman", "Helvetica", "Courier" int style[] = }; { Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD + Font.ITALIC }; String styleName[] = { " " " " plain", bold", italic", bold-italic"

}; public void paint(Graphics gDC) { for(int n = 1, i = 0; i < typeFace.length ; i++) { String fontName = typeFace[i]; for(int j = 0; j < style.length ; j++) { int fontStyle = style[i]; Font font = new Font(fontName, fontStyle, 12); gDC.setFont(font); string = fontName + styleName[j]; gDC.drawString(string, 10, 15 * n++); } }

117

} }

Metryka
Kompletny zestaw waciwoci czcionki opisuje jej metryka. Metody operujce na metryce nale do klasy abstrakcyjnej FontMetrics. Uwaga: Badanie metryki moe dotyczy tylko czcionki takiego komponentu, ktry moe by wykrelony na ekranie. Wanymi parametrami metryki s uniesienie obnienie wiato wysoko (ascent) (descent) (leading) (height) odlego midzy lin bazow, a szczytem znaku, jak w literze , odlego midzy lini bazow, a podstaw znaku, jak w literze g, odstp poniej podstawy znaku, suma uniesienia, obnienia i wiata.

Uwaga: Lini bazow (base line) jest linia na ktrej spoczywaj znaki, np. jak w Hello.
public int getAscent()

Metoda zwraca uniesienie w pikselach.


public int getDescent()

Metoda zwraca obnienie w pikselach.


public int getLeading()

Metoda zwraca wiato w pikselach.


public int getHeight()

Metoda zwraca wysoko czcionki w pikselach. Nastpujcy program, pokazany podczas wykonania na ekranie Metryka czcionki, ilustruje posugiwanie si waniejszymi parametrami czcionki. Ekran Metryka czcionki
### metrics.gif <applet code=Master.class width=300 height=150> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Font font = new Font("Arial", Font.BOLD, 80); static String string = "fgA"; static int xBase = 10, yBase; int strAscent, strDescent, strHeight, strLeading; static int strWidth; public void init() { Toolkit toolKit = Toolkit.getDefaultToolkit(); FontMetrics mtx = toolKit.getFontMetrics(font); strWidth = mtx.stringWidth(string); strAscent = mtx.getAscent(); strDescent = mtx.getDescent(); strHeight = mtx.getHeight(); strLeading = strHeight - (strAscent + strDescent); yBase = strHeight + 10; } public void paint(Graphics gDC) {

118

gDC.setFont(font); gDC.drawString(string, xBase + 50, yBase); draw(gDC, "BaseLine", 0); draw(gDC, "AscentLine", strAscent); draw(gDC, "DescentLine", -strDescent); draw(gDC, "", -strDescent-strLeading); } static void draw(Graphics gDC, String str, int h) { int xBase = Master.xBase, yBase = Master.yBase; gDC.drawLine(xBase, yBase-h, xBase+ 50 + 10 + strWidth, yBase-h); Font oldFont = gDC.getFont(), newFont = new Font("TimesRoman", Font.ITALIC, 10); gDC.setFont(newFont); gDC.drawString(str, xBase, yBase-h); gDC.setFont(oldFont); } }

Kolory
Wzorcowym modelem koloru jest RGB. W modelu RGB kady kolor mona przedstawi jako trjk skadnikw RGB w ktrej R (red), G (green), B (blue) okrelaj ile w kolorze jest skadnika czerwonego, zielonego i niebieskiego. W szczeglnoci, kolor RGB(255,255,0), w ktrym wystpuje maksymalna ilo czerwieni i zieleni, ale nie ma skadnika niebieskiego, jest kolorem tym. W programie wynikowym kolor jest reprezentowany przez czwrk bajtw aRGB w ktrej a jest skadnikiem alfa, reprezentujcym przeroczysto koloru, a R, G, B s skadnikami koloru o wartociach z przedziau 0..255 wcznie. Jeli skadnik alfa ma warto 0, to kolor jest cakowicie przeroczysty (transparent), a jeli ma warto 255, to jest cakowicie nieprzeroczysty (opaque). Domnieman wartoci alfa jest 255. Kilkanacie typowych kolorw ma oznaczenia symboliczne podane w tabeli Symbole kolorw. Tabela Symbole kolorw
### Color.black Color.darkGray Color.lightGray Color.pink ### Color.blue Color.gray Color.magenta Color.red Color.yellow Color.cyan Color.green Color.orange Color.white

Kolor biecy
Z kadym kontekstem graficznym jest zwizany kolor biecy. Ustawienie i pobranie koloru biecego odbywa si za pomoc procedur setColor i getColor.
public void setColor(Color color)

Metoda ustawia kolor biecy na kolor podany.


public Color getColor()

Metoda zwraca odnonik do odrbnego obiektu opisujcego kolor biecy.

119

Nastpujcy program, pokazany podczas wykonywania na ekranie Model kolorw, ilustruje sposb przekazywania informacji o kolorze z opisu apletu Ekran Model kolorw
### rgbcolor.gif <applet code=Master.class width=160 height=60> <param name=Color value=ff00ff> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Color color; int rgbColor = 0;; public void init() { String color = getParameter("Color"); try { rgbColor = Integer.parseInt(color, 16); } catch(NumberFormatException e) { showStatus("Wrong format"); } this.color = new Color(rgbColor); } public void paint(Graphics gDC) { gDC.setColor(color); gDC.drawString("Hello", 20, 20); } }

Wykonanie programu powoduje wywietlenie napisu Hello w kolorze purpurowym. Gdyby parametrowi Color nadano warto 0xff00ff, to spowodowaoby to wysanie wyjtku klasy NumberFormatException, a napis zostaby wywietlony w kolorze czarnym.

Kolor lica i kolor ta


Z kadym komponentem s zwizane dwa kolory: kolor lica (foreground) i kolor ta (background). Do zarzdzania nimi su metody getForeground i setForeground oraz getBackground i setBackground.
public void setForeground(Color color)

Metoda ustawia kolor lica komponentu na podany.


public void setBackground(Color color)

Metod ustawia kolor ta komponentu na podany.


public Color getForeground()

Metoda zwraca kolor lica komponentu.


public Color getBackground()

Metoda zwraca kolor ta komponentu. Nastpujcy aplet, pokazany podczas wykonania na ekranie Kolory lica i ta, ilustruje zasad okrelania koloru komponentw. Ekran Kolory lica i ta
### foreback.gif <applet code=Master width=160 height=100> </applet> =========================================

120

import java.applet.*; import java.awt.*; public class Master extends Applet { Button button; public void init() { add(button = new Button("OK")); setBackground(Color.white); setForeground(Color.red); } public void paint(Graphics gDC) { gDC.drawOval(10, 10, 80, 80); } public boolean action(Event evt, Object arg) { boolean flag = evt.target == button; if(flag) button.setBackground(Color.black); return flag; } }

Kliknicie przycisku powoduje zmian jego koloru na czarny.

Tryb XOR
Czsto istnieje potrzeba wykrelenia i wytarcia wykrelonego obiektu, ale bez naruszenia ta. Do tego celu dobrze nadaje si wykrelanie w trybie XOR. Ma ono t waciwo, e dwukrotne wykrelenie tego samego obiektu przywraca pierwotny stan ta.
public void setXORMode(Color color)

Metoda przygotowuje wykrelacz do wykrelania w trybie XOR z kolorem color. Powoduje to, e piksel wykrelony w kolorze biecym zachowa ten kolor na tle o podanym kolorze, a na tle w swoim kolorze przyjmie podany kolor. Zmiana pozostaych kolorw nie jest przewidywalna, ale po ponownym wykreleniu nastpi przywrcenie kolorw pierwotnych. Nastpujcy aplet, pokazany podczas wykonania na ekranie Odtwarzanie ta, umoliwia przeciganie okrgu bez naruszenia kolorowego napisu stanowicego to. Ekran Odtwarzanie ta
### xormode.gif

Przykad Odtwarzanie ta
<applet code=Master width=400 height=100> </applet> ========================================= import java.applet.*; import java.awt.*; public class Master extends Applet { Font font = new Font("TimesRoman", Font.BOLD, 60); final int r = 20; int xOld, yOld; public void init() { setBackground(Color.green); } public void paint(Graphics gDC) { gDC.setFont(font); gDC.setColor(Color.red); gDC.drawString("Drag over me!", 10, 60);

121

} public boolean mouseDown(Event evt, int x, int y) { drawRing(xOld = x, yOld = y); return true; } public boolean mouseDrag(Event evt, int x, int y) { drawRing(xOld, yOld); drawRing(xOld = x, yOld = y); return true; } public boolean mouseUp(Event evt, int x, int y) { drawRing(x, y); return true; } void drawRing(int x, int y) { Graphics gDC = getGraphics(); gDC.setColor(Color.red); gDC.setXORMode(Color.green); int l = x-r, t = y-r, w = 2*r, h = 2*r; for(int i = 0; i < 5 ; i++) gDC.drawOval(l+i, t+i, w-2*i, h-2*i); } }

W celu uproszczenia kodu apletu nie obsuono sytuacji kiedy przeciganie zakoczy si po za pulpitem apletu. W takim przypadku przecigany piercie nie zostanie usunity z ekranu.

_________________________________________________________________________________________

Myszka
W typowych przypadkach nie jest istotne, ktry z przyciskw myszki zosta uyty do wykonania akcji. Jednak zbadanie stanu modyfikatorw Alt (przycisk rodkowy) i Meta (przycisk prawy) umoliwia dokonanie takiego rozstrzygnicia. Jeli myszka jest wyposaona w przycisk zwizany z modyfikatorem Alt albo Meta, to jest on ustawiany niejawnie. W przeciwnym razie ustawienie modyfikatora musi by zasymulowane przez nacinicie klawisza Alt albo Meta. W szczeglnoci, jeli myszka jest dwu-przyciskowa, to uycie prawego przycisku powoduje niejawne ustawienie modyfikatora Meta, ale w celu zasymulowania rodkowego przycisku (i ustawienia modyfikatora Alt) naley wraz z uyciem przycisku myszki, dodatkowo nacisn klawisz Alt. Uwaga: Opisany efekt mona zaobserwowa wykonujc aplet pod przegldark Netscape. W rodowisku Cafe nacinicie klawisza Alt powoduje wyrnienie menu Applet, a wic nie moe by rozpoznane przez badanie modyfikatora. W tabeli Maski klawiszy wymieniono maski zwizane z modyfikatorami Alt i Meta oraz dodatkowo maski klawiszy Shift i Ctrl. Tabela Maski klawiszy
### Event.SHIFT_MASK Event.CTRL_MASK Event.ALT_MASK Event.META_MASK ### nacinito nacinito nacinito nacinito klawisz klawisz klawisz klawisz Shift Ctrl Alt Meta

Nastpujcy aplet, pokazany podczas wykonania na ekranie Przyciski myszki, wywietla nazw nacinitego klawisza myszki. Ekran Przyciski myszki
### mouse.gif <applet code=Master.class width=160 height=100> </applet> =============================================== import java.applet.*; import java.awt.*;

122

public class Master extends Applet { public void paint(Graphics gDC) { gDC.drawString("Press mouse button!", 10, 20); } public boolean mouseDown(Event evt, int x, int y) { int mods = evt.modifiers; String button; if((mods & Event.ALT_MASK) != 0) button = "MIDDLE"; else if((mods & Event.META_MASK) != 0) button = "RIGHT"; else button = "LEFT"; Graphics gDC = getGraphics(); gDC.drawString("You pressed " + button + " button!", x, y); return true; } public boolean mouseUp(Event evt, int x, int y) { repaint(); return true; } }

Jeli zostanie nacinity prawy klawisz myszki, to w punkcie kliknicia wywietli si napis
You pressed RIGHT button!

_________________________________________________________________________________________

Klawiatura
Zdarzenia KEY_PRESS i KEY_RELEASE dotycz zwykych klawiszy (wszystkie znaki drukowalne, a ponadto: Enter, Tab, Esc, Backspace, Del), a zdarzenia KEY_ACTION i KEY_ACTION_RELEASE dotycz klawiszy funkcyjnych. Klawisze funkcyjne maj oznaczenia podane w tabeli Klawisze funkcyjne. Tabela Klawisze funkcyjne
### Event.HOME Event.END Event.PGUP Event.PGDOWN Event.UP Event.DOWN Event.LEFT Event.RIGHT Event.F1 Event.F2 ... Event.F12 ### klawisz klawisz klawisz klawisz klawisz klawisz klawisz klawisz Home End PgUp PgDn Up (strzalka Dn (strzaka Lt (strzaka Rt (strzaka

w w w w

gr) d) lewo) prawo)

klawisz F1 klawisz F2 ... klawisz F12

Badanie, czy wraz z naciniciem klawisza nacinito jeden z klawiszy modyfikujcych: Shift, Ctrl, Alt, Meta odbywa si za pomoc masek. Nastpujcy aplet, pokazany podczas wykonania na ekranie Nazwy klawiszy, wywietla nazw nacinitego klawisza. Ekran Nazwy klawiszy
### keys.gif <applet code=Master.class width=360 height=80> </applet> ==============================================

123

import java.applet.*; import java.awt.*; public class Master extends Applet { Font font = new Font("Arial", Font.BOLD, 60); String keyName = ""; public void paint(Graphics gDC) { gDC.setFont(font); gDC.drawString(keyName, 20, 60); } public boolean keyDown(Event evt, int key) { if(evt.id == Event.KEY_PRESS) keyName = getModKeys(evt) + getRegKeyName(evt); else if(evt.id == Event.KEY_ACTION) keyName = getModKeys(evt) + getFunKeyName(evt); repaint(); return true; } String getModKeys(Event evt) { int flags = evt.modifiers; boolean notEnter = evt.key != 10; String string = ""; if(evt.shiftDown() && notEnter) string += "Shift-"; if((flags & Event.ALT_MASK) != 0 && notEnter) string += "Alt-"; if(evt.metaDown() && notEnter) string += "Meta-"; if(evt.controlDown() && notEnter) string += "Ctrl-"; return string; } String getRegKeyName(Event evt) { if(evt.key == 10) return "Enter"; char chr = (char)evt.key; if(evt.controlDown() && chr < ' ') return "" + (char)(chr + '`'); else switch(chr) { case '\t': return "Tab"; case '\33': return "Esc"; case '\10': return "Backspace"; } if(chr == '\177') return "Delete"; if(chr == ' ') return "Space"; return "" + chr; } String getFunKeyName(Event evt) { int key = evt.key; switch(key) { case Event.HOME: return "Home"; case Event.END: return "End"; case Event.PGUP: return "PgUp"; case Event.PGDN: return "PgDn"; case Event.UP: return "Up"; case Event.DOWN: return "Down";

124

case Event.LEFT: return "Lt"; case Event.RIGHT: return "Rt"; default: int offF1 = key - Event.F1; return "F" + (1 + offF1); } } }

_________________________________________________________________________________________

Kursory
Podczas wykonywania operacji graficznych w oknach mona posugiwa si zestawem standardowych kursorw. Ksztat kursora identyfikuj liczby cakowite, ktre mona wyraa za pomoc symboli podanych w tabeli Kursory. Wygld kursora zaley od uytego systemu. W Windows 95 kursor oczekiwania (delay) ma wygld klepsydry, a w MacOS ma wygld zegarka. Tabela Kursory
###

Kursor
Frame.DEAFAULT_CURSOR Frame.TEXT_CURSOR Frame.WAIT_CURSOR Frame.CROSSHAIR_CURSOR Frame.HAND_CURSOR ###

Wygld
wskanik karetka oczekiwanie krzyak do

public int getCursorType()

Metoda zwraca liczb identyfikujc kursor (np. Frame.TEXT_CURSOR).


public void setCursor(int shape)

Metoda okrela ksztat kursora jaki ma obowizywa w oknie. Nastpujcy aplet, pokazany podczas wykonania na ekranie Ksztat kursora, umoliwia wykrelanie prostokta za pomoc kursora w ksztacie krzyaka (za spraw programu PaintShopPro, uytego do zdejmowania ekranw, krzyak nie jest widoczny na przytoczonej ilustracji). Ekran Ksztat kursora
### cursor.gif <applet code=Master.class width=160 height=60> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Frame frame; public void init() { frame = new MyFrame("Draw a box"); } public void paint(Graphics gDC) { gDC.drawString("Drag in FRAME", 10, 25); } } class MyFrame extends Frame { Graphics gDC; MyFrame(String caption) {

125

super(caption); resize(150, 120); show(); gDC = getGraphics(); } int xAnchor, yAnchor, xOld, yOld; Color backColor; public boolean mouseDown(Event evt, int x, int y) { xAnchor = xOld = x; yAnchor = yOld = y; backColor = getBackground(); return true; } int abs(int par) { if(par < 0) return -par; return par; } int min(int one, int two) { if(one < two) return one; return two; } public boolean mouseDrag(Event evt, int x, int y) { Color color = gDC.getColor(); gDC.setColor(backColor); int w = xOld - xAnchor, h = yOld - yAnchor; int l = min(xAnchor, xOld), t = min(yAnchor, yOld); gDC.drawRect(l, t, abs(w), abs(h)); gDC.setColor(color); w = (xOld = x) - xAnchor; h = (yOld = y) - yAnchor; l = min(xAnchor, x); t = min(yAnchor, y); gDC.drawRect(l, t, abs(w), abs(h)); return true; } public boolean mouseUp(Event evt, int x, int y) { repaint(); return true; } }

Wykrelany prostokt znika w chwili zwolnienia przycisku myszki. _________________________________________________________________________________________

Obrazy
Obrazy s adowane z plikw. W celu zaadowania obrazu, znajdujcego si w pliku sieci globalnej, naley poda jego lokalizator URL. Poniewa czsto zdarza si, e adowany obraz znajduje si w tym samym katalogu co kod albo opis apletu, dobrze jest pamita o metodach getCodeBase i getDocumentBase. Rozpoznawane s tylko obrazy zapisane w formatach GIF i JPEG. Inne formaty wymagaj wasnego dekodowania. Format GIF stosuje kompresj bezstratn, a format JPEG stosuje transformacj z utrat elementw obrazu. Dlatego format GIF jest przydatny do przekazywania tekstw i zrzutw ekranu, a format JPEG do przekazywania fotografii. adowanie obrazw odbywa si za pomoc metod getImage, a ich wykrelanie za pomoc metod drawImage. Jeli aplet podejmie prb zaadowania obrazu z innego miejsca ni sam pochodzi, to zostanie wysany wyjtek klasy SecurityException.

126

public Image getImage(URL whereURL)

Zapocztkowanie pobrania obrazu z miejsca okrelonego przez lokalizator whereUrl.


public Image getImage(URL baseURL, String fileName)

Zapocztkowanie pobrania obrazu z pliku fileName znajdujcego si w katalogu okrelonym przez baseURL.
public boolean drawImage(Image img, int x, int y, ImageObserver imgObs)

Zapocztkowanie wykrelania obrazu img, pod nadzorem obserwatora imgObs, w prostokcie, ktrego lewy-grny naronik znajduje si w punkcie (x, y).
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver imgObs)

Zapocztkowanie wykrelania przeskalowanego obrazu img, pod nadzorem obserwatora imgObs, w prostokcie o rozmiarach width x height, ktrego lewy-grny naronik znajduje si w punkcie (x, y).
public boolean drawImage(Image img, int x, int y, int width, int height, Color backColor, ImageObserver imgObs)

Zapocztkowanie wykrelania przeskalowanego obrazu img, pod nadzorem obserwatora imgObs, w prostokcie o rozmiarach width x height, ktrego lewy-grny naronik znajduje si w punkcie (x, y) i z kolorem ta backColor (istotne podczas wykrelania obrazw z przeroczystymi pikselami). Wykonanie nastpujcego programu, pokazanego podczas wykonania na ekranie Obraz WinZip, powoduje wywietlenie obrazu z pliku WinZip.gif, znajdujcego si w tym samym katalogu co plik zawierajcy opis apletu. Ekran Obraz WinZip
### grab.gif <applet code=Master.class width=420 height=100> <param name=Grab value=WinZip.gif> </applet> =============================================== import java.applet.*; import java.awt.*; import java.net.*; public class Master extends Applet { private static Image myImage; int width, height; public void init() { String what = getParameter("Grab"); URL where = getDocumentBase(); myImage = getImage(where, what); width = myImage.getWidth(this); height = myImage.getHeight(this); } public void paint(Graphics gDC) { gDC.drawImage(myImage, 0, 0, width, height, Color.black, this); } }

Informacje o rozmiarach apletu pobrano z jego opisu. Obraz przeskalowano w taki sposb, aby zaj cay pulpit apletu.

Obserwacja
127

Mimo mylcej nazwy, wykonanie metody getImage jedynie zapocztkowuje cignicie obrazu z sieci. Dopiero wykonanie metody drawImage powoduje sukcesywne, w miar postpujcej transmisji, wywietlanie kolejnych fragmentw obrazu. To sukcesywne wywietlanie jest nadzorowane przez obserwatora, ktrym jest obiekt klasy implementujcej interfejs ImageObserver. Interfejs ImageObserver implementuje m.in. klasa Component, a wic i klasa Applet. Dlatego w wywoaniu metod drawImage moe wystpi odnonik this identyfikujcy obserwatora. Uwaga: Interfejs ImageObserver zawiera deklaracj tylko jednej metody: imageUpdate.
public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height)

Metoda imageUpdate jest wywoywana przez System wielokrotnie, w miar postpujcego adowania obrazu. Jeli zwrci warto true, to bdzie wywoana ponownie, a jeli zwrci false, to dla danej operacji nie bdzie ju wywoywana. W ciele metody imageUpdate mona odwoywa si m.in. do nastpujcych flag bitowych
WIDTH

Jest dostpna szeroko obrazu, okrelona przez parametr width.


HEIGHT

Jest dostpna wysoko obrazu, okrelona przez parametr height.


SOMEBITS

Jest dostpna nastpna porcja bitw obrazu. Ograniczajcy j prostokt jest okrelony cznie przez parametry ( x,y) i width x height.
ALLBITS

Jest dostpny cay obraz.


ERROR

Wystpi bd. Inne informacje nie bd ju dostarczone. Obrazu nie da si wykreli. Nastpujcy aplet, pokazany podczas wykonania na ekranie Obserwowanie adowania, ilustruje zasad posugiwania si obserwatorem adowania obrazu. Ekran Obserwowanie adowania
### observer.gif <applet code=Master.class width=160 height=100> <param name=Photo value=Duke.gif> </applet> =============================================== import import import import java.applet.*; java.awt.*; java.awt.image.*; java.net.*;

public class Master extends Applet implements ImageObserver { boolean done; private static Image myImage; public void init() { String what = getParameter("Photo"); URL where = getDocumentBase(); myImage = getImage(where, what); } public void paint(Graphics gDC) { done = gDC.drawImage(myImage, 0, 0, this); } public boolean imageUpdate(Image img, int flags,

128

int x, int y, int width, int height) { if((flags & ImageObserver.ALLBITS) != 0) { showStatus("Image fully loaded"); Graphics gDC = getGraphics(); gDC.drawImage(img, x, y, null); // wykrelenie return false; } else { if((flags & ImageObserver.HEIGHT) == 0) showStatus("Loading ... "); else showStatus("Loaded " + height); return true; } } }

Przebieg wykrelania obrazu jest obserwowany. Komunikaty o przebiegu adowania s wywietlane w wierszu stanu apletu.

Nadzr
Nadzorowanie adowania wikszej liczby obrazw zapewnia nadzorca mediw. Jego rol peni obiekt klasy MediaTracker. Dziki nadzorcy mediw mona zainicjowa adowanie wikszej liczby obrazw, na przykad zestawu kadrw animacji, a do czasu ich cignicia z sieci wykonywa inne czynnoci. Kada operacja zlecona nadzorcy jest rejestrowana i opatrywana unikatowym identyfikatorem. Zapytania o przebieg wykonania operacji wymagaj podania identyfikatora. Kilka metod nadzorcy mediw zwraca flagi bitowe okrelajce postp adowana obrazw. Do ich badania mona uy symboli wymienionych w tabeli Flagi adowania. Tabela Flagi adowania
###

LOADING ABORTED ERRORED COMPLETE


###

Trwa adowania adowanie/adowania zarzucono adowanie/adowania nie powiody si adowanie/adowania zakoczono

boolean waitForID(int id)

Metoda wstrzymuje wykonanie wtku do chwili zakoczenia adowania wszystkich obrazw opatrzonych podanym identyfikatorem.
boolean waitForAll()

Metoda wstrzymuje wykonanie wtku do chwili zakoczenia adowania wszystkich obrazw.


int statusId(int id, boolean load)

Metoda zwraca flagi opisujce przebieg adowania obrazu o podanym identyfikatorze.


int statusAll(boolean load)

Metoda zwraca flagi opisujce adowanie wszystkich obrazw. Nastpujcy aplet, pokazany podczas wykonania na ekranie Nadzorowanie adowania, ilustruje uycie nadzorcy mediw. Ekran Nadzorowanie adowania
### tracker.gif <applet code=Master.class width=220 height=100> <param name=Count value=3> <param name=Prefix value=Photo> <param name=Photo1 value=Duke1.gif> <param name=Photo2 value=Duke2.gif> <param name=Photo3 value=Duke3.gif> </applet>

129

=============================================== import import import import java.applet.*; java.awt.*; java.net.*; java.util.*;

public class Master extends Applet { int count; Image photos[]; static MediaTracker tracker; int width, height; public void init() { tracker = new MediaTracker(this); URL where = getCodeBase(); try { String count = getParameter("Count"); this.count = Integer.parseInt(count); } catch(NumberFormatException e) { this.count = 0; } photos = new Image [count+1]; String prefix = getParameter("Prefix"); for(int i = 1; i < count+1 ; i++) { String parName = prefix + i, fileName = getParameter(parName); photos[i] = getImage(where, fileName); tracker.addImage(photos[i], i); } int failCount = 0; for(int i = 1; i < count+1 ; i++) { try { tracker.waitForID(i); } catch(InterruptedException e) { } if(tracker.isErrorID(i)) failCount++; } if(failCount != 0) { showStatus("No. of failures: " + failCount); } width = photos[1].getWidth(this); height = photos[1].getHeight(this); } public void paint(Graphics gDC) { Thread thisThread = Thread.currentThread(); for(int i = 1; i < count+1 ; i++) { gDC.drawImage(photos[i], width*(i-1), 0, width, height, Color.black, this); try { thisThread.sleep(200); } catch(InterruptedException e) { } } } }

Sprawdza si, e obrazy zostay pomylnie zaadowane, a dopiero po tym przystpuje si do ich wywietlenia.

_________________________________________________________________________________________ 130

Rozkady
Sposb rozmieszczenia komponentw w pojemniku: w aplecie, w panelu albo w ramce okrela zarzdca rozkadu (Layout Manager). Do najczciej uywanych nale zarzdcy FlowLayout, BorderLayout i GridLayout. W chwili utworzenia pojemnika jest mu przypisywany zarzdca domylny (np. dla apletu FlowLayout, a dla ramki BorderLayout). Nic jednak nie stoi na przeszkodzie, aby zarzdca zosta zmieniony na dowolny inny, take ju po zaadowaniu pojemnika. Rozmieszczenie komponentw w pojemniku moe si odbywa bez udziau zarzdcy. W takim wypadku pooenie i rozmiar kadego z komponentw naley okreli jawnie, za pomoc metod reshape albo resize i move klasy Component.
public void resize(int width, int height)

Zmiana rozmiarw komponentu na podane.


public synchronized void reshape(int x, int y, int width, int height)

Zmiana pooenia i rozmiarw komponentu na podane.


public void move(int x, int y)

Zmiana pooenia lewego-grnego naronika komponentu na podane. Nastpujcy aplet, pokazany podczas wykonania na ekranie Bez zarzdcy, nie posuguje si zarzdc rozkadu. Ekran Bez zarzdcy
### null.gif <applet code=Master.class width=300 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { Panel panel = nullLayoutPanel(); panel.resize(200, 200); setLayout(null); add(panel); } Panel nullLayoutPanel() { Panel panel = new Panel(); panel.setLayout(null); Button red = new Button("Red"), green = new Button("Green"), blue = new Button("Blue"); TextField cell = new TextField("Hello"); panel.add(red); panel.add(green); panel.add(blue); panel.add(cell); red.reshape(0, 0, 60, 30); green.reshape(70, 0, 60, 30); blue.reshape(140, 0, 60, 30); cell.reshape(0, 40, 100, 30); return panel; } }

131

FlowLayout
Rozkad cigy (FlowLayout) polega na rozmieszczaniu komponentw jeden-za-drugim. Jeli zestaw komponentw nie mieci si w wierszu pojemnika, to kolejny komponent jest przenoszony do nastpnego wiersza.
public FlowLayout() public FlowLayout(int align) public FlowLayout(int align, int hGap, int vGap)

Konstruktory okrelaj waciwoci rozkadu, w tym sposb wyrwnania komponentw ( align: FlowLayout.LEFT, FlowLayout.RIGHT, FlowLayout.CENTER) oraz poziomy (hGap) i pionowy (vGap) odstp midzy komponentami. Na ekranie Rozkad cigy pokazano aplet, w ktrym zastosowano rozkad FlowLayout. Ekran Rozkad cigy
### flow.gif <applet code=Master.class width=160 height=80> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { Panel panel = flowLayoutPanel(); add(panel); } Panel flowLayoutPanel() { Panel panel = new Panel(); panel.setLayout(new FlowLayout(FlowLayout.RIGHT)); panel.add(new Button("Greet")); panel.add(new Button("Clear")); return panel; } }

Przyciski Greet i Clear wyrwnano prawostronnie w wierszu pulpitu.

BorderLayout
Rozkad brzegowy (BorderLayout) polega na rozmieszczeniu komponentw na obrzeach i w rodku pojemnika. Obrzea maj nazwy stron wiata: West, East, North, South. rodek pojemnika ma nazw Center.
public Borderlayout() public BorderLayout(int hGap, int vGap)

Konstruktory okrelaj waciwoci rozkadu. Drugi z nich dodatkowo: poziomy ( hGap) i pionowy (vGap) odstp midzy komponentami. Na ekranie Rozkad brzegowy pokazano aplet, w ktrym zastosowano rozkad BorderLayout. Ekran Rozkad brzegowy
### border.gif <applet code=Master.class width=400 height=80> </applet> ============================================== import java.applet.*; import java.awt.*;

132

public class Master extends Applet { public void init() { Panel panel = borderLayoutPanel(); add(panel); } Panel borderLayoutPanel() { Panel panel = new Panel(); panel.setLayout(new BorderLayout()); panel.add("East", new Button("Greet")); panel.add("West", new Button("Clear")); panel.add("North", new TextField(8)); panel.add("Center", new Label("The Center")); panel.add("South", new TextArea()); return panel; } }

GridLayout
Rozkad siatkowy (GridLayout) polega na rozmieszczeniu komponentw w ukadzie prostoktnej siatki o podanych rozmiarach. Wszystkie jej klatki maj identyczne rozmiary.
public GridLayout(int rows, int cols) public GridLayout(int rows, int cols, int hGap, int vGap)

Konstruktory okrelaj liczb wierszy (rows) i kolumn (cols) rozkadu oraz poziomy (hGap) i pionowy (vGap) odstp midzy komponentami. Na ekranie Rozkad siatkowy pokazano aplet, w ktrym zastosowano rozkad GridLayout. Ekran Rozkad siatkowy
### grid.gif <applet code=Master.class width=240 height=160> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { Panel panel = gridLayoutPanel(); add(panel); } Panel gridLayoutPanel() { Panel panel = new Panel(); panel.setLayout(new GridLayout(4, 4, 10, 10)); for(int k = 0, row = 0; row < 4 ; row++) for(int col = 0; col < 4 ; col++) if(k++ == 0) panel.add(new Button("Clear")); else panel.add(new Button("Greet" + (k-1))); return panel; } }

_________________________________________________________________________________________

Sterowniki
133

Sterownikami s komponenty rozmieszczane w najgbszych pojemnikach. Typowymi sterownikami s: etykieta (Label), przycisk (Button), klatka (TextField), notatnik (TextArea) i ptno (Canvas). Etykieta i notatnik s sterownikami biernymi (nie mog obsugiwa zdarze).

Label
Etykieta jest sterownikiem umoliwiajcym umieszczenie w pojemniku dowolnie sformatowanego napisu. Napis moe by wyrwnany: lewostronnie (Label.LEFT), prawostronnie (Label.RIGHT) albo rodkujco (Label.CENTER). Na ekranie Etykiety pokazano aplet zawierajcy sterowniki Label. Ekran Etykiety
### label.gif <applet code=Master.class width=100 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { setLayout(new BorderLayout()); Label left = new Label("Left"); Label right = new Label("Right", Label.RIGHT); add("North", left); add("South", right); add("Center", new Label("Center", Label.CENTER)); } }

Button
Przycisk jest sterownikiem, ktrego nacinicie (kliknicie przyciskiem myszki) moe by obsuone, co zazwyczaj powoduje wykonanie akcji. Zaleca si, aby rodzaj akcji odpowiada napisowi wykrelonemu na przycisku. Uwaga: Po wygenerowaniu zdarzenia ACTION_EVENT opis przycisku jest dostpny poprzez (String)evt.arg. Na ekranie Przyciski pokazano aplet zawierajcy sterowniki Button. Ekran Przyciski
### button.gif <applet code=Master.class width=300 height=160> </applet> =============================================== import java.applet.*; import java.awt.*; import java.util.*; public class Master extends Applet { private Panel panel = new Panel(); Label target = new Label("", Label.CENTER); public void init() { panel.setLayout( new FlowLayout(FlowLayout.RIGHT, 10, 3) ); String java = "Java is very easy to learn"; StringTokenizer phrase = new StringTokenizer(java); while(phrase.hasMoreTokens())

134

panel.add(new MyButton(phrase.nextToken(), target)); setLayout(new BorderLayout()); add("Center", panel); add("South", target); Font font = new Font("Arial", Font.BOLD, 60); target.setFont(font); } } class MyButton extends Button { Label target; MyButton(String label, Label target) { super(label); this.target = target; } public boolean action(Event evt, Object arg) { target.setText((String)arg); return true; } }

Kade ze sw frazy
Java is very easy to learn

jest wywietlane na osobnym przycisku. Nacinicie przycisku opatrzonego wybranym sowem (np. easy) powoduje wywietlenie go w dolnej czci apletu.

TextField
Klatka jest sterownikiem, do ktrego mona wprowadzi tekst. Podczas wprowadzania tekstu mona posugiwa si klawiszami kierunkowymi oraz klawiszami Del i Backspace. Uwaga: Po naciniciu klawisza Enter jest generowane zdarzenie ACTION_EVENT. Podczas obsugiwania go zawarto klatki jest dostpna poprzez zmienn (String)evt.arg. Na ekranie Klatki pokazano aplet zawierajcy sterowniki TextField. Ekran Klatki
### field.gif <applet code=Master.class width=240 height=80> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { TextField firstName = new TextField(20), lastName = new TextField(20); Label firstNameLabel = new Label("First name: ", Label.RIGHT), lastNameLabel = new Label("Last name: ", Label.RIGHT); setLayout(new FlowLayout()); add(firstNameLabel); add(firstName); add(lastNameLabel); add(lastName); } public boolean action(Event evt, Object arg) { String entry = arg.toString();

135

((TextField)evt.target).setText(entry.toUpperCase()); return true; } }

Po naciniciu klawisza Enter nastpuje zmiana liter wprowadzonych do klatki z maych na due.

TextArea
Notatnik jest sterownikiem implementujcym prosty edytor. Edytor jest wyposaony w suwaki. Czynne s klawisze strzakowe oraz Enter, Backspace i Delete. Notatnik reaguje tylko na nacinicia klawiszy oraz na czynnoci wykonane za pomoc myszki (zmienna evt.arg nie ma interpretacji). Metody appendText, insertText i replaceText umoliwiaj przetwarzanie tekstu wprowadzonego do notatnika.
public void appendText(String str)

Metoda dokleja acuch str na kocu notatnika.


public void insertText(String str, int pos)

Metoda wstawia acuch str przed znakiem na pozycji pos notatnika.


public void replaceText(String str, int f, int t)

Metoda zastpuje wycinek znakw notatnika midzy jego pozycjami f i t, acuchem str. Na ekranie Notatnik pokazano aplet zawierajcy sterownik TextArea. Ekran Notatnik
### area.gif <applet code=Master.class width=300 height=120> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { TextArea textArea; public void init() { String aProgram = " public " class Simplest { " public static " void main(String args[]) " { " } " }

\n" + \n" + \n" + \n" + \n" + \n" + \n";

int width = Integer.parseInt(getParameter("width")), height = Integer.parseInt(getParameter("height")); textArea = new TextArea(aProgram, 100, 40); setLayout(null); add(textArea); textArea.reshape(0, 0, width, height); } public boolean handleEvent(Event evt) { if(evt.id == Event.KEY_ACTION && evt.key == Event.F5 && (evt.modifiers & Event.CTRL_MASK) != 0) { textArea.insertText(" final\n", 0); return true; } return false; }

136

} Wykonanie programu powoduje wywietlenie notatnika zawierajcego kod najkrtszej aplikacji. Po naciniciu klawisza Ctrl-F5, przed pierwszy wiersz tego programu jest wstawiany napis
final

Canvas
Ptno jest sterownikiem, pozbawionym predefiniowanej semantyki (jak na przykad przycisk). Na ptnie mona umieszcza dowolne sterowniki. Mona rwnie sporzdza na nim wykresy. Uwaga: Ptno reaguje tylko na nacinicia klawiszy oraz na czynnoci wykonane za pomoc myszki (zmienna evt.arg nie ma interpretacji). Na ekranie Ptna pokazano nastpujcy aplet zawierajcy sterowniki Canvas. Ekran Ptna
### canvas.gif <applet code=Master.class width=180 height=180> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { setLayout(new GridLayout(5, 5)); for(int shade = 0, row = 0; row < 5 ; row++) for(int col = 0; col < 5 ; col++) { Canvas canvas = new RedCircle(shade += 10); add(canvas); } } } class RedCircle extends Canvas { int shade; RedCircle(int shade) { this.shade = shade; } public void paint(Graphics gDC) { gDC.setColor(new Color(shade, 0, 0)); gDC.fillOval(0, 0, 35, 35); gDC.setColor(Color.white); gDC.fillOval(0, 0, 15, 15); } public boolean mouseUp(Event evt, int x, int y) { Graphics gDC = getGraphics(); gDC.drawLine(0, 0, x, y); return true; } }

Wykonanie programu powoduje m.in. wywietlenie zestawu okrgw zabarwionych na czerwono, kady w innym odcieniu.

MenuItem
Polecenie jest sterownikiem umoliwiajcym wyposaenie ramki w menu. 137

Menu jest komponentem klasy Menu, a polecenie menu jest sterownikiem klasy MenuItem. Wybieranie polece odbywa si przez kliknicie. Uwaga: Po wygenerowaniu zdarzenia kategorii ACTION_EVENT etykieta polecenia menu jest dostpna poprzez zmienn (String)evt.arg. Na ekranie Menu pokazano aplet, ktry posuguje si odrbn ramk zawierajc sterowniki MenuItem. Ekran Menu
### menuitem.gif <applet code=Master.class width=180 height=180> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Frame greetFrame; Label label = new Label("Choose greeting from menu"); public void init() { greetFrame = new MyFrame("Greet", label); greetFrame.resize(200, 200); greetFrame.show(); setLayout(new FlowLayout()); add(new Button("Show / Hide")); int width = Integer.parseInt(getParameter("width")), height = Integer.parseInt(getParameter("height")); greetFrame.resize(width, height); MenuBar menuBar = new MenuBar(); greetFrame.setMenuBar(menuBar); Menu fileMenu = new Menu("File"); fileMenu.add(new MenuItem("-")); // separator fileMenu.add(new MenuItem("Exit")); menuBar.add(fileMenu); Menu greetMenu = new Menu("Greet"); greetMenu.add(new MenuItem("Say Hello")); greetMenu.add(new MenuItem("Say Hi")); menuBar.add(greetMenu); Menu helpMenu = new Menu("Help"); helpMenu.add(new MenuItem("About")); menuBar.add(helpMenu); menuBar.setHelpMenu(helpMenu); // wyrwnanie w prawo greetFrame.setLayout(new BorderLayout()); greetFrame.add("South", label); } public boolean handleEvent(Event evt) { if(evt.arg.equals("Show / Hide")) { if(greetFrame.isShowing()) greetFrame.hide(); else greetFrame.show(); return true; } return false; } } class MyFrame extends Frame { Label label; MyFrame(String caption, Label label) { super(caption);

138

this.label = label; } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) dispose(); // obsuga kliknicia na x if(evt.arg.equals("Say Hello")) { label.setText("Hello Jan B."); return true; } else if(evt.arg.equals("Say Hi")) { label.setText("Hi Jan B."); return true; } else if(evt.arg.equals("Exit")) { dispose(); return true; } else if(evt.arg.equals("About")) { label.setText("Copyright JanB."); return true; } return false; } }

Program ilustruje sposb reagowania na polecenia menu, w ktre wyposaono ramk utworzon przez aplet.

_________________________________________________________________________________________

Pojemniki
Pojemnik jest komponentem, ktry moe zawiera w sobie inne komponenty: pojemniki i sterowniki. Gboko zagniedania komponentw w pojemnikach nie jest ograniczona. Na kadym poziomie zagniedenia moe by uyty inny zarzdca rozkadu. Poza apletem, typowymi pojemnikami s: panel (Panel), ramka (Frame) i dialog (FileDialog).

Panel
Panel jest pojemnikiem o domylnym rozkadzie FlowLayout. Panel zawierajcy sterowniki jest traktowany jak pojedynczy komponent i jako taki moe by umieszczony w innym pojemniku. Nastpujcy program, pokazany podczas wykonywania na ekranie Panele, tworzy dwa panele i rozmieszcza je w grnej i dolnej czci apletu z rozkadem brzegowym. Ekran Panele
### panels.gif <applet code=Master.class width=160 height=80> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Label label; Button tom, bob; public void init() { Panel panel = new Panel(); panel.add(tom = new Button("Tom")); panel.add(bob = new Button("Bob")); setLayout(new BorderLayout()); add("North", panel); add("South", panel); add("Center", label = new Label("Press a Button")); } public boolean action(Event evt, Object arg) { if(evt.target == tom) label.setText("Hello Bob");

139

else if(evt.target == bob) label.setText("Hello Tom"); else return false; return true; } }

Kliknicie przycisku Tom powoduje wykrelenie napisu


Hello Bob

a kliknicie przycisku Bob powoduje wykrelenie napisu


Hello Tom

Frame
Ramka jest pojemnikiem z domniemanym zarzdc rozkadu BorderLayout. Ramka reaguje na zdarzenia zwizane z operacjami wykonywanymi za pomoc myszki i klawiatury. Nastpujcy program, pokazany podczas wykonania na ekranie Ramki, wywietla 10 ramek stowarzyszonych z apletem, a w kadej z nich wykrela jedn cyfr. Ekran Ramki
### frames.gif <applet code=Master.class width=160 height=80> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { public void init() { for(int i = 0; i < 10 ; i ++) { Frame frame = new MyFrame(i); frame.reshape(10 * (i+1), 10 * (i+1), 100, 100); frame.show(); } } } class MyFrame extends Frame { int digit; Font font = new Font("TimesRoman", Font.BOLD, 60); MyFrame(int digit) { this.digit = digit; } public void paint(Graphics gDC) { gDC.setFont(font); gDC.drawString("" + digit, 50, 50); } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) dispose(); return false; } }

Dialog
140

Dialog plikowy jest pojemnikiem uatwiajcym zaadowanie i zachowanie pliku. Umoliwia on wywietlenie okna z pytaniami o stacj, ciek i plik. Obiekty dialogowe s tworzone za pomoc konstruktorw klasy FileDialog, a wywietlenie dialogu odbywa si za pomoc metody show. Operacje na zmiennych obiektu dialogowego s wykonywane m.in. za pomoc metod getFile, getDirectory oraz setFile i setDirectory.
public FileDialog(Frame parent, String caption, int mode)

Konstruktor tworzy dialog zaadowania albo zachowania (SAVE). Rodzaj dialogu mona okreli za pomoc argumentu mode (FileDialog.LOAD, albo FileDialog.SAVE).
public FileDialog(Frame parent, String caption)

Konstruktor tworzy dialog zaadowania (LOAD).


public void show()

Metoda wywietla dialog opisany przez obiekt dialogowy.


public String getFile()

Metoda zwraca nazw pliku.


public String getDirectory()

Metoda zwraca nazw katalogu.


public void setFile(String file)

Metoda ustawia nazw pliku.


public void setDirectory(String dir)

Metoda ustawia nazw katalogu. Nastpujcy aplet, pokazany podczas wykonania na ekranie Dialog plikowy, ilustruje zasad posugiwania si dialogiem plikowym. Ekran Dialog plikowy
### dialog.gif <applet code=Master.class width=160 height=80> </applet> ============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { Frame frame = new Frame("Parent"); String dir, file; public void init() { frame.show(); add(new Button("Load")); add(new Button("Save")); } public boolean action(Event evt, Object arg) { if(evt.target instanceof Button) { FileDialog fileDialog = null; if(arg.equals("Save")) { fileDialog = new FileDialog(frame, "Save", FileDialog.SAVE); } if(arg.equals("Load")) { fileDialog = new FileDialog(frame, "Load", FileDialog.LOAD); } fileDialog.show();

141

dir = fileDialog.getDirectory(); file = fileDialog.getFile(); repaint(); return true; } return false; } public void paint(Graphics gDC) { gDC.drawString("Dir: " + dir, 10, 50); gDC.drawString("File: " + file, 10, 70); } }

Program wywietla nazw katalogu i pliku, wybrane w oknie dialogu plikowego.

_________________________________________________________________________________________

Kontrolki
Kontrolk jest sterownik stanowicy kompozycj komponentw. Komponenty zaleca si wyposay w metody minimumSize i preferredSize, a na rzecz kontrolki wywoa metod validate. W przeciwnym razie moe si zdarzy, e elementy kontrolki nie bd waciwie wykrelane.
public Dimension minimumSize()

Metoda okrela minimalny rozmiar komponentu.


public Dimension preferredSize()

Metoda okrela ulubiony rozmiar komponentu.


public void validate()

Metoda powoduje ponowne przeliczenie rozmiarw i pooenia komponentu.

Uwaga: Jedynym sposobem dodania metody minimumSize i preferredSize do klasy predefiniowanej (np. Button), jest utworzenie jej podklasy. Na przykad
class MyButton extends Button { MyButton(String caption) { super(caption); } public Dimension minimumSize() { return new Dimension(20, 20); } // ... }

Klasa MyButton moe by uywana w taki sam sposb jak klasa Button. Od klasy Button rni si wasn metod minimumSize. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Kontrolka, ilustruje sposb wykorzystania wasnego sterownika (zdefiniowanego za pomoc klas Display i Key), z trjwymiarowymi przyciskami umoliwiajcymi wprowadzanie liczb cakowitych. Uwaga: Przycisk S kontrolki oprogramowano w taki sposb, aby umoliwia wyeksportowanie liczby ze sterownika (klasa Display definiuje sterownik-wywietlacz, a klasa Key sterownik-przycisk). Ekran Kontrolka
### display.gif <applet code=Master.class width=130 height=180>

142

</applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet { private Display theDisplay; private TextField theCell; public void init() { setLayout(new BorderLayout()); theCell = new TextField("Ready"); theDisplay = new Display(); add("North", theCell); add("East", theDisplay); } public boolean mouseUp(Event evt, int x, int y) { int value = theDisplay.getValue(); theCell.setText(String.valueOf(value)); return true; } }

Aplet tworzy klatk tekstow i wywietlacz z przyciskami. Procedura mouseUp rozpoznaje nacinicie przycisku S wywietlacza i obsuguje je w taki sposb, e liczb znajdujc si w wywietlaczu wstawia do klatki.

Klasa Display
Klasa Display definiuje wywietlacz z przyciskami. Zwolnienie przycisku S nie powoduje obsuenia tego zdarzenia (po naciniciu przycisku S metoda mouseUp zwraca false). Stwarza to moliwo obsuenia go w pojemniku kontrolki.
class Display extends Panel { private int value = 0; private Panel display = new Panel(); private TextField number = new TextField("0"); private Panel buttons = new Panel(); private static String labels = "7894561230 S"; private char lastKey = '0'; Display() { display.setLayout(new BorderLayout()); buttons.setLayout(new GridLayout(4, 3)); for(int i = 0; i < 12 ; i++) { char chr = labels.charAt(i); Key key = new Key(this, chr); buttons.add(key); } display.add("North", number); display.add("Center", buttons); add(display); } public void setLastKey(char key) { lastKey = key; } int getValue() { return value; } void setValue(int value) { this.value = value; number.setText(new String("" + value)); } public boolean handleEvent(Event evt) { if(evt.id == Event.MOUSE_UP)

143

return mouseUp(evt, evt.x, evt.y); return true; } public boolean mouseUp(Event evt, int x, int y) { switch(lastKey) { case ' ': value = 0; number.setText("0"); return true; case 'S': return false; // nie obsuono, posano dalej default: int digit = lastKey - '0'; value = value * 10 + digit; number.setText(String.valueOf(value)); return true; } } }

Klasa Key
Klasa Key definiuje trjwymiarowy przycisk wywietlacza. Efekt trjwymiarowoci uzyskano przez wykrelenie ukw w kolorze czarnym i biaym. Wybrany rozmiar przyciskw okrela metoda preferredSize. Nacinicie przycisku wywietlacza powoduje wykrelenie go w postaci wcinitej. Zwolnienie przycisku powoduje zapamitanie wcinitego przycisku, ale bez obsuenia tego zdarzenia (metoda mouseUp zwraca false). Umoliwia to obsuenie tego zdarzenia w pojemniku-wywietlaczu Display.
class Key extends Panel { Display display; private char theKey; private Color color; private boolean mouseIsDown = false; Key(Display display, char theKey) { this.display = display; this.theKey = theKey; } public boolean mouseDown(Event evt, int x, int y) { mouseIsDown = true; repaint(); return true; } public boolean mouseUp(Event evt, int x, int y) { mouseIsDown = false; repaint(); display.setLastKey(theKey); return false; } public void paint(Graphics gDC) { Rectangle bounds = bounds(); int w = bounds.width, h = bounds.height; Color oldColor = gDC.getColor(); drawOval(gDC, Color.red, 0, 0, w, h); int x = (w /= 2) / 2, y = (h /= 2) / 2; drawOval(gDC, Color.green, x, y, w, h); gDC.setColor(oldColor); drawLabel(gDC, theKey, x, y, w, h); } void drawOval(Graphics gDC, Color color, int x, int y, int w, int h) { gDC.setColor(color);

144

gDC.fillOval(x, y, w, h); color = mouseIsDown ? Color.white : Color.black; gDC.setColor(color); gDC.drawArc(x, y, w, h, 45, -180); color = mouseIsDown ? Color.black : Color.white; gDC.setColor(color); gDC.drawArc(x, y, w, h, 45, +180); } public void drawLabel(Graphics gDC, char label, int x, int y, int w, int h) { Font font = new Font("Arial", Font.BOLD, 12); gDC.setFont(font); FontMetrics metrics = gDC.getFontMetrics(); int as = metrics.getAscent(), ww = metrics.charWidth(label); x += (w - ww) / 2; y += (h + as) / 2; gDC.drawString("" + label, x, y); } public Dimension preferredSize() { return new Dimension(30, 30); } public Dimension minimumSize() { return new Dimension(30, 30); } }

Porednik-Obserwator-Kontroler
Wykorzystujc bez zmian zdefiniowane powyej klasy Display i Key, mona poda uoglnione rozwizanie postawionego problemu. Stanowi ono ilustracj metody komunikowania si sterownikw znanej pod nazw Porednik-Obserwator-Kontroler (Model-View-Controller). Istot metody jest skonstruowanie klasy obiektw poredniczcych, ktre mog by jednoczenie obserwowane i kontrolowane. Jeli obiekt-kontroler dokona modyfikacji obiektu-porednika, to za pomoc metody update zostanie o tym powiadomiony obiekt-obserwator. Kontroler i obserwator nic o sobie nie wiedz i komunikuj si tylko poprzez porednika. Dziki temu modyfikacja jednego z tych sterownikw nie ma adnego wpywu na drugi. Czyni to program prawdziwie modularnym i zmniejsza niebezpieczestwo niekontrolowanego propagowania zmian kodu. Wykonanie nastpujcego programu, w ktrym rol porednika, obserwatora i kontrolera peni odpowiednio obiekty klas ObservableInt, ObserverTextField i ControllerDisplay ma taki sam skutek jak uprzednio. Ponadto, wprowadzenie do klatki tekstowej pewnej liczby, powoduje przeniesienie jej do klatki wywietlacza. W szczeglnoci, gdyby metod
public void update(Observable obs, Object arg) { setValue(theInt.getInt()); }

zastpiono metod
public void update(Observable obs, Object arg) { return; }

to nacinicie klawisza Enter w obrbie klatki tekstowej anulowaoby przeniesienie liczby do wywietlacza. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Kontrolka dla koneserw, ilustruje zastosowanie metody PorednikObserwator-Kontroler. Ekran Kontrolka dla koneserw
### control.gif

145

Przykad Kontrolka dla koneserw


<applet code=Master.class width=130 height=180> </applet> =============================================== import java.applet.*; import java.awt.*; import java.util.*; public class Master extends Applet { private Display theDisplay; private TextField theCell; ObservableInt theInt = new ObservableInt(0); public void init() { setLayout(new BorderLayout()); theCell = new ObserverTextField(theInt, "Ready"); theDisplay = new ControllerDisplay(theInt); add("North", theCell); add("East", theDisplay); } } class ObservableInt extends Observable { int theInt; ObservableInt(int theInt) { this.theInt = theInt; } public synchronized int getInt() { return theInt; } public synchronized void setInt(int newInt) { if(newInt != theInt) { theInt = newInt; setChanged(); notifyObservers(); } } } class ObserverTextField extends TextField implements Observer { ObservableInt theInt; ObserverTextField(ObservableInt theInt, String string) { this.theInt = theInt; theInt.addObserver(this); setText(string); } public boolean action(Event evt, Object arg) { String string = (String)arg; int value; try { value = Integer.parseInt(string); } catch(NumberFormatException e) { setText("Not a Number"); return true; } theInt.setInt(value); return true; } public void update(Observable obs, Object arg) { setText("" + theInt.getInt()); } }

146

class ControllerDisplay extends Display implements Observer { ObservableInt theInt; ControllerDisplay(ObservableInt theInt) { this.theInt = theInt; theInt.addObserver(this); } public boolean handleEvent(Event evt) { if(!super.handleEvent(evt)) theInt.setInt(getValue()); return true; } public void update(Observable obs, Object arg) { setValue(theInt.getInt()); } }

_________________________________________________________________________________________

Dwiki
W chwili obecnej s rozpoznawane tylko pliki dwikowe w formacie AU. W celu odtworzenia dwikw zarejestrowanych w innych formatach naley dokona ich konwersji. Jednym z lepszych produktw do wykonania tego zadania jest program Wham dostpny w Internecie. Do zaadowania pliku dwikowego i utworzenia identyfikujcego g o obiektu klasy AudioClip suy metoda getAudioClip, a do zarzdzania plikami dwikowymi metody loop, play i stop wywoywane na rzecz takiego obiektu.
public AudioClip getAudioClip(URL url, String fileName)

Metoda aduje plik dwikowy fileName, znajdujcy si pod adresem url.


public abstract void loop()

Wywoanie metody loop powoduje cykliczne odtwarzanie podanego dwiku.


public abstract void play()

Wywoanie metody play powoduje odegranie podanego dwiku.


public abstract void stop()

Wywoanie metody stop powoduje zaniechanie dalszego odgrywania dwiku. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Melodie, odgrywa dwie melodie: jedn cyklicznie w tle (z pliku Gong.au) i drug co 1 s (z pliku Ding.au). Ekran Melodie
### melody.gif <applet code=Master.class width=100 height=100> </applet> =============================================== import import import import java.applet.*; java.awt.*; java.net.*; java.util.*;

public class Master extends Applet implements Runnable { private AudioClip backGround; private AudioClip foreGround; Thread player = null; Random rand = new Random(); public void init() {

147

URL from = getCodeBase(); backGround = getAudioClip(from, "Gong.au"); foreGround = getAudioClip(from, "Ding.au"); } public void start() { if(backGround != null) backGround.loop(); if(player == null) { player = new Thread(this); player.start(); } } public void stop() { if(player != null) { player.stop(); player = null; } if(backGround != null) backGround.stop(); } public void run() { while(player != null) { if(foreGround != null) { drawCircle(); foreGround.play(); } try { Thread.sleep(1000); } catch(InterruptedException e) { } } } int abs(int par) { return par < 0 ? -par : par; } void drawCircle() { int d = 10; int x = rand.nextInt() % (100-d), y = rand.nextInt() % (100-d); Graphics gDC = getGraphics(); gDC.drawOval(abs(x), abs(y), d, d); } }

Przed kadym odegraniem dwiku z pliku Ding.au jest wykrelane mae kko. Jego pooenie na pulpicie apletu jest przypadkowe.

_________________________________________________________________________________________

Animacje
Animacja polega na sukcesywnym generowaniu albo odtwarzaniu sekwencji kadrw. Generowanie i wywietlanie kadrw odbywa si zazwyczaj w odrbnym wtku. Program apletu realizujcego animacj (a do kliknicia lewym przyciskiem myszki), przybiera zazwyczaj posta
import java.applet.*; import java.awt.*; public class Master extends Applet implements Runnable { // ... Thread engine;

148

boolean stopped = false; // ... public void init() { // ... przygotowanie pierwszego kadru } public void start() { if(engine == null) { // utworzenie wtku // implementowanego przez // metod run engine = new Thread(this); // aktywowanie wtku engine.start(); } } public void stop() { if(engine != null && engine.isAlive()) // zniszczenie wtku engine.stop(); engine = null; } public void paint(Graphics gDC) { // ... wykrelenie kadru } public boolean mouseUp(Event evt, int x, int y) { return stopped = true; } public void run() { while(!stopped) { // ... przygotowanie kolejnego kadru repaint(); try { engine.sleep(100); } catch(InterruptedException e) { } // ... } } }

Generowanie
Nastpujcy aplet, pokazany podczas wykonywania na ekranie Generowanie kadrw, powoduje wywietlenie maego okrgu poruszajcego si po elipsie. Obraz okrgu, w jego kolejnych pooeniach, jest generowany w odstpach co 100 ms. Ekran Generowanie kadrw
### circle.gif <applet code=Master.class width=160 height=160> </applet> =============================================== import java.applet.*; import java.awt.*; public

149

class Master extends Applet implements Runnable { static final int r = 5; static final double Pi = Math.PI; static final int steps = 24; static final double step = 2 * Pi/steps; Thread rotor; boolean stopped = false; static double startAngle = Pi/4; int width, height; double xSubAxis, ySubAxis, angle; public void init() { width = Integer.parseInt( getParameter("width") ); height = Integer.parseInt( getParameter("height") ); xSubAxis = width /2 - 2*r; ySubAxis = height/2 - 2*r; } public void start() { if(rotor == null) { rotor = new Thread(this); rotor.start(); } } public void stop() { if(rotor != null && rotor.isAlive()) rotor.stop(); rotor = null; } public void paint(Graphics gDC) { int width = (int)(2 * xSubAxis), height = (int)(2 * ySubAxis); gDC.drawOval(r, r, width, height); int x = (int)(r + xSubAxis * (1 + Math.cos(angle))), y = (int)(r + ySubAxis * (1 - Math.sin(angle))); gDC.drawOval(x - r, y - r, 2*r, 2*r); } public boolean mouseUp(Event evt, int x, int y) { return stopped = true; } public void run() { while(!stopped) { repaint(); try { rotor.sleep(100); } catch(InterruptedException e) { } angle += step; } } }

150

Buforowanie
Poniewa kade wywoanie metody repaint powoduje wyczyszczenie pulpitu, wic prosta animacja odbywa si z niezbyt przyjemnym dla oka migotaniem obrazu. Mona temu zaradzi, stosujc buforowanie. Polega ono na przygotowaniu obrazu w buforze pamici operacyjnej, a nastpnie rzuceniu zawartoci bufora na ekran. Istot buforowania wyjania nastpujcy wycinek programu
// okrelenie rozmiarw apletu Dimension d = size(); int w = d.width, h = d.height; // utworzenie bufora w pamici operacyjnej backBuffer = createImage(w, h); // utworzenie wykrelacza zwizanego z buforem Graphics gDC = backBuffer.getGraphics(); // przygotowanie obrazu za pomoc metody paint paint(gDC); // utworzenie wykrelacza zwizanego z pulpitem gDC = getGraphics(); // skopiowanie bufora na pulpit gDC.drawImage(backBuffer, 0, 0, this);

Nastpujcy aplet, pokazany podczas wykonania na ekranie Buforowanie, wykorzystuje technik buforowania do generowania kadrw. Ekran Buforowanie
### buffer.gif <applet code=Master.class width=160 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; public class Master extends Applet implements Runnable { static final int r = 5; static final double Pi = Math.PI; static final int steps = 24; static final double step = 2 * Pi/steps; Thread rotor; boolean stopped = false; static double startAngle = Pi/4; int width, height; double xSubAxis, ySubAxis, angle; Image backBuffer; public void init() { width = Integer.parseInt( getParameter("width") ); height = Integer.parseInt( getParameter("height") ); xSubAxis = width /2 - 2*r; ySubAxis = height/2 - 2*r; } public void start() {

151

if(rotor == null) { rotor = new Thread(this); rotor.start(); } } public void stop() { if(rotor != null && rotor.isAlive()) rotor.stop(); rotor = null; } public void paint(Graphics gDC) { int width = (int)(2 * xSubAxis), height = (int)(2 * ySubAxis); gDC.drawOval(r, r, width, height); int x = (int)(r + xSubAxis * (1 + Math.cos(angle))), y = (int)(r + ySubAxis * (1 - Math.sin(angle))); gDC.drawOval(x - r, y - r, 2*r, 2*r); } public void run() { while(!stopped) { Dimension d = size(); int w = d.width, h = d.height; backBuffer = createImage(w, h); Graphics gDC = backBuffer.getGraphics(); paint(gDC); // wykrelenie do bufora gDC = getGraphics(); gDC.drawImage(backBuffer, 0, 0, this); try { rotor.sleep(100); } catch(InterruptedException e) { } angle += step; } } }

W odrnieniu od poprzedniego przykadu, to wykresu jest biae.

Odtwarzanie
Nastpujcy aplet, pokazany podczas wykonania na ekranie Odtwarzanie kadrw, wywietla obracajce si migo. Kolejne kadry animacji pochodz z pliku Turbo.gif. Do upewnienia si, e animacja rozpocznie si dopiero po przygotowaniu kadrw, wykorzystano zarzdc mediw. Do wywietlania kolejnych kadrw zastosowano technik buforowania. Ekran Odtwarzanie kadrw
### propel.gif

Ekran Plik Turbo.gif


### turbo.gif <applet code=Master.class width=160 height=160> <param name=Image value=Turbo.gif> </applet> =============================================== import java.applet.*; import java.awt.*; import java.net.*;

152

public class Master extends Applet implements Runnable { Thread engine; boolean stopped = false; MediaTracker tracker; String imgFrames; Image imageFrames; Image backBuffer; static final int frameSize = 160; static final int frameCount = 8; int pos = 0, xPos = 0; public void init() { imgFrames = getParameter("Image"); // utworzenie zarzdcy mediw tracker = new MediaTracker(this); URL codeBase = getCodeBase(); // zainicjowanie pobrania obrazu imageFrames = getImage(codeBase, imgFrames); // powierzenie zarzdcy mediw // nadzoru sprowadzenia obrazu tracker.addImage(imageFrames, 1); try { // wstrzymanie wykonania apletu // do chwili sprowadzenia obrazu tracker.waitForID(1); } catch(InterruptedException e) { } } public void start() { if(engine == null) { engine = new Thread(this); engine.start(); } } public void stop() { if(engine != null && engine.isAlive()) engine.stop(); engine = null; } public void paint(Graphics gDC) { gDC.drawImage(imageFrames, xPos, 0, null); } public boolean mouseUp(Event evt, int x, int y) { return stopped = true; } public void run() { while(!stopped) { xPos = -pos * frameSize; Dimension d = size(); int w = d.width, h = d.height; backBuffer = createImage(w, h); Graphics gDC = backBuffer.getGraphics(); paint(gDC); gDC = getGraphics(); gDC.drawImage(backBuffer, 0, 0, this); try { engine.sleep(100); }

153

catch(InterruptedException e) { } pos = ++pos % frameCount; } } }

Pozornie jest wykrelany kompletny zestaw kadrw, ale dziki ujemnej wsprzdnej xPos i ograniczeniu wykrelania do pulpitu apletu, jest kadorazowo wykrelany tylko jeden kadr.

_________________________________________________________________________________________

Przesyanie
Aplet pochodzcy z sieci rozlegej moe komunikowa si tylko z serwerem z ktrego zosta zaadowany. W szczeglnoci, jeli aplet zaadowano na podstawie opisu znajdujcego si pod adresem
http://www.janb.com/java/cafe/text.html

to moe on wykonywa operacje wejcia-wyjcia tylko spod adresu


http://www.janb.com/java/cafe/File

w ktrym File jest nazw pliku (np. subdir/source.doc) Uwaga: Midzy adresem komputera (tu: www.janb.com) a ciek do File moe wystpi niejawna cieka poredniczca wstawiona tam przez serwer. Przykad Przesyanie danych
<applet code=Master.class width=100 height=100> </applet> =============================================== import import import import java.applet.*; java.awt.*; java.net.*; java.io.*;

public class Master extends Applet { URL url; int EOF = StreamTokenizer.TT_EOF; String text = ""; public void init() { try { url = new URL( "http://" + "www.janb.com/java/cafe/" + "greet.txt" ); } catch(MalformedURLException e) { } StreamTokenizer tokens = null; try { tokens = new StreamTokenizer(url.openStream()); while(tokens.nextToken() != EOF) text += tokens.sval; } catch(IOException e) { } } public void paint(Graphics gDC) { gDC.drawString(text, 10, 20); }

154

Wykonanie apletu powoduje wywietlenie zawartoci pliku greet.txt znajdujcego si w katalogu, z ktrego pochodzi aplet. Podczas uruchamiania apletu mona plik greet.txt umieci na dysku lokalnym i zamiast adresu
http://www.janb.com/java/cafe/greet.txt

poda na przykad adres


file:///c:/java/cafe/greet.txt

_________________________________________________________________________________________

Komunikacja
Komunikowanie si apletw, ktrych opisy znajduj si w tym samym pliku HTML, wymaga nadania im nazw. Nazwy apletw podaje si w opisach apletw we frazie name. Nastpujcy program, pokazany podczas wykonania na ekranie Komunikacja, ilustruje zasad komunikowania si apletw, nazwanych One i Two. Kliknicie pulpitu jednego z nich powoduje wykrelenie okrgu na pulpicie drugiego. Opisy apletw w dokumencie HTML s rne, ale B-kod obu apletw jest wsplny. Ekran Komunikacja
### onetwo.gif <applet code=Master.class width=160 height=100 name=One> </applet> <applet code=Master.class width=160 height=100 name=Two> </applet> ======================================================== import java.applet.*; import java.awt.*; public class Master extends Applet { String name; Thread myThread = null; public void init() { name = getParameter("name"); } Applet otherApplet() { String other = null; if(name.equals("One")) other = "Two"; if(name.equals("Two")) other = "One"; AppletContext context = getAppletContext(); return context.getApplet(other); } public boolean mouseDown(Event evt, int x, int y) { Applet other = otherApplet(); Graphics gDC = other.getGraphics(); gDC.drawOval(x - 20, y - 20, 40, 40); return true; } public boolean mouseUp(Event evt, int x, int y) { otherApplet().repaint(); return true; } }

155

_________________________________________________________________________________________

Przeczenia
Aplet mona zaprojektowa w taki sposb, aby wykonanie operacji na jego sterowniku powodowao przeczenie na inny dokument HTML, ni ten z ktrego pochodzi wanie wywietlany aplet. Nastpujcy aplet, pokazany podczas wykonywania na ekranie Wyszukiwarki, ilustruje zasad przeczania stron dokumentw HTML. Kliknicie jednego z przyciskw przywouje na ekran stron domow jednej z ze znanych wyszukiwarek: AltaVista, HotBot i Yahoo. Ekran Wyszukiwarki
### yahoo.gif <applet code=Master.class width=160 height=100> </applet> =============================================== import java.applet.*; import java.awt.*; import java.net.*; public class Master extends Applet { public void init() { add(new Button("AltaVista")); // wyszukiwarka add(new Button("HotBot")); // wyszukiwarka add(new Button("Yahoo")); // wyszukiwarka } public boolean action(Event evt, Object arg) { URL newURL = null; try { if(!(evt.target instanceof Button)) return false; if(arg.equals("Alta Vista")) newURL = new URL("http://altavista.digital.com/"); else if(arg.equals("Hot Bot")) newURL = new URL("http://hotbot.com/"); else newURL = new URL("http://www.yahoo.com/"); } catch(MalformedURLException e) { } AppletContext context = getAppletContext(); context.showDocument(newURL); return true; } }

156

Literatura
Bielecki, J.: Java po C++, Intersoftland, 1996. (zwiza i treciwa, dla programujcych w C++) The Java Class Libraries, Addison Wesley, 1996. (doskonaa, szczegowy opis bibliotek, w tym AWT) The Java Language Specification, Addison Wesley, 1996. (doskonaa, obszerny opis jzyka, bez opisu AWT) Java in a Nutshell, O'Reilly & Associates, 1996. (doskonaa, ciekawe przykady, zwize opisy bibliotek) On to Java, Addison Wesley, 1996. (doskonaa, wysza spod rki zawodowego dydaktyka) Teach Yourself Java in 21 Days, Sams Net, 1996. (dobra dla pocztkujcych, uproszczona i niecisa) The Java Tutorial, JavaSoft, 1996. (dobra dla pocztkujcych, ciekawa i szczegowa) The Java Programming Language, JavaSoft, 1996. (przecitna, wiele bdw, mimo wspautorstwa J.G.) Java By Example, The SunSoft Press, 1996. (niekompletna, atwa, dobra dla pocztkujcych) Just Java, The SunSoft Press, 1996. (taka sobie, dla niezbyt wymagajcych) Java Unleashed, Sams Net, 1996. (przegadana, ale atwa i szczegowa) The Java Handbook, Osborne/McGraw-Hill, 1996. (warta uwagi ze wzgldu na autora, dobra dla pocztkujcych) Using Java, QUE, 1996. (obszerna, taka sobie, kilka ciekawych pomysw) Instant Java, The SunSoft Press, 1996. (ciekawy zbir gotowych apletw, nie do nauki jzyka) Writing Java Applets, Coriolis Group Books, 1996. (przecitna, gwnie o programowaniu sieciowym)

Chan, P.: Gosling, J.: Flanagan, D.: Winston, P.:

LeMay, L.: Walrath, K.:

Arnold, K.: McClellan, A.: Linden, P.: Morrison, M.: Naughton, P.: Newman, A.: Pew, J.: Rodley, J:

157

Sownik terminw

158

A
abort abrubt accessible active alpha component ambiguous applet ascent zaniecha gwatowny dostpny aktywny skadnik alfa dwuznaczny aplet uniesienie to linia bazowa migotanie orzeczenie orzecznik jaskrawo przegldarka buforowanie przycisk B-kod obsuga ptno karta konwersja znacznik nastawa wybr odbiorca pulpit obcinanie klon zgodny wspbieny poczenie wymuszenie konsument pojemnik sterownik przepyw sterowania punkt charakterystyczny konstruktor kopiujcy sekcja krytyczna wycinanie biecy zamwiony demon datagram impas uruchamiacz domylny definitywny oczekiwanie zniechca obnienie dialog katalog domena przeciga opada zrzut

B
background baseline blinking boolean value boolean variable brightness browser buffering button bytecode

C
callback canvas card cast check mark checkbox choice client client area clipping clone compatible concurrent connection constraint consumer container control control flow control point copy constructor critical section cropping current custom

D
daemon datagram deadlock debugger default definitive delay deprecate descent dialog directory domain drag drop down dump

E
159

elaboration ellipsis embedded envelope environment event driven event

opracowanie wielokropek wbudowany koperta, otoczka otoczenie sterowany zdarzeniami zdarzenie wyraenie fabrykujce metoda fabrykujca plik filtrowany ustalony zapora przepyw sterowania wymie katalog lico ramka zaprzyjanienie nieuytek kontekst graficzny obsuga sterta wysoko strona domowa gospodarz odcie identyfikator przyrostowy inicjator egzemplarz integralno oblicze l-wyraenie etykieta rozkad wiato czenie lista adowanie lokalizator zarzdca skadnik metryka dominujcy wielodziedziczenie wielowtkowy rodzimy zawenie pusty obserwator nieprzeroczysty przeciony przedefiniowa 160

F
factory expression factory method file filtered final firewall flow of control flush folder foreground frame friendship

G
garbage graphics context

H
handler heap height home page host hue

I
identifier incremental initializer instance integrity interface

L
l-value label layout leading linking list loading locator

M
manager member metrics modal multiple inheritance multithreaded

N
native narrowing null

O
observer opaque overloaded override

P
package passive peer pipe pointer port portable preempt preferred prepared priority process producer property protocol pakiet bierny rwnorzdny potok pozycja port przenony wywaszczy ulubiony przygotowany priorytet proces producent waciwo protok przecznik ranga wskrzesi rekurencyjny wielobieny odnonik obszar wzgldny wizualizacja cykliczny zwiza spoczywa wielouytkowy zaokrglenie wykonywa nasycenie zakres bezpieczestwo samodzielny dostawca sesja przesoni pytki dzielony skutek uboczny sygnatura rozmiar spa gniazdo rdo zagodzony strumie pie styl podklasa nadklasa utrzymywany zawieszony cel zadanie kasjer notatnik klatka wtek nadzorca 161

R
radio button rank reanimate recursive reentrant reference region relative rendering repetetive resolve rest reusable rounding run

S
saturation scope security self contained server session shadow shallow shared side effect signature size sleep socket source starved stream stub style subclass superclass supported suspended

T
target task teller text area text field thread tracker

transient transparent typeface

nietrway przeroczysty krj niezrwnowaony weryfikowa pozorny ulotny czeka poszerzenie sterownik

U
unbalanced

V
verify virtual volatile

W
wait widening widget

162

Dodatki

163

Dodatek A
Priorytet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Priorytety operatorw
Wizanie lewe prawe prawe lewe lewe lewe lewe lewe lewe lewe lewe lewe lewe prawe prawe Operator ++ -- (nastpnikowe) ++ -- (poprzednikowe) + - ~ ! (Type) * / % + << >> >>> < <= > >= instanceof == != & ^ | && || ?: = *= /= %= += -= <<= >>= >>>= &= ^= |=

Nastpujce zestawienie wyszczeglnia peen zestaw operatorw, wraz z ich priorytetami i wizaniami.

164

Dodatek B

Parametry zdarze

Nastpujce zestawienie okrela w jaki sposb komponenty reaguj na zdarzenia. W nawiasach podano jakie spord pl arg, when, x, y, modifiers maj interpretacj dla wymienionych komponentw. Pola target nie wymieniono, bo ma interpretacj zawsze.
ACTION_EVENT Button Checkbox Choice List MenuItem TextField MOUSE_DOWN MOUSE_UP MOUSE_MOVE MOUSE_DRAG Component MOUSE_ENTER MOUSE_EXIT Component LIST_SELECT LIST_DESELECT List GOT_FOCUS LOST_FOCUS Component KEY_PRESS KEY_RELAEASE KEY_ACTION KEY_ACTION_RELEASE Component SCROLL_LINE_UP SCROLL_LINE_DOWN SCROLL_PAGE_UP SCROLL_PAGE_DOWN SCROLL_ABSOLUTE Scrollbar WINDOW_DESTROY WINDOW_EXPOSE WINDOW_ICONIFY WINDOW_DEICONIFY WINDOW_MOVED Window wykonanie akcji na sterowniku przycisk (arg: etykieta nastawa (arg: nowy stan wybr (arg: etykieta lista (arg: etykieta polecenie (arg: etykieta klatka (arg: zawarto

String) boolean) String) String) String) String)

nacinicie przycisku myszki zwolnienie przycisku myszki przemieszczenie kursora przecignicie kursora (when, x, y, modifiers) wejcie kursora w obszar komponentu wyjcie kursora z obszaru komponentu (when, x, y) wyrnienie elementu listy usunicie wyrnienia (arg: indeks uzyskanie gotowoci do odbierania znakw utrata gotowoci

int)

nacinicie zwykego klawisza zwolnienie zwykego klawisza nacinicie klawisza funkcjyjnego zwolnienie klawisza funkcyjnego (when, x, y, key, modifiers) mae przewinicie do przodu (wiersz, znak) mae przewinicie wstecz due przewinicie do przodu (strona) due przewinicie wstecz przewinicie na pozycj (arg: pozycja int) zniszczenie okna odsonicie okna zmniejszenie okna do ikony powikszenie ikony do okna przemieszczenie okna (x, y)

165

Dodatek C

Klasa uruchomieniowa

Zdefiniowana tu klasa uruchomieniowa Debug uatwia wyszukiwanie bdw wystpujcych podczas wykonywania aplikacji i apletw. Wykonanie instrukcji
new Debug();

powoduje utworzenie ramki, w ktrej s wywietlane argumenty przecionej funkcji toFrame oraz funkcji assert. Uwaga: Przed uyciem klasy Debug w wersji rdowej naley upewni si, e modu zawiera polecenie
import java.awt.*;

Na przykad
Debug.toFrame("Hello"); Debug.toFrame(var+1); Debug.toFrame("var = " + var); Debug.toFrame(Thread.currentThread()); Debug.assert("In paint: boxWidth > 5", boxWidth > 5);

Bezporednio po wywoaniu funkcji off, a przed najbliszym wywoaniem funkcji on, wstrzymuje si wywietlanie argumentw metod toFrame i assert. Uwaga: Jeli nie wywoano konstruktora klasy Debug, to wywoywanie jej funkcji jest ignorowane. Na przykad
new Debug(100, 100); // ... Debug.off(); // ... Debug.on(); // ... // wywoanie konstruktora // zaniechanie wywietlania // przywrcenie wywietlania

Uwaga: Wykonanie operacji new Debug() moe by tylko jednokrotne. W przypadku naruszenia tego wymagania jest wysyany wyjtek klasy InstantiationError.
import java.awt.*; class Debug { /** Klasa uruchomieniowa Copyright Jan Bielecki */ static Frame frame; String header = "Debug\n=====\n"; static TextArea textArea; static boolean opened = false; static boolean active = false; Debug() { this(200, 400); } Debug(int width, int height) { if(opened) throw new InstantiationError(); opened = true; active = true; frame = new DebugFrame("Debug"); frame.resize(width, height); textArea = new TextArea(header); // wymagane zawsze

166

frame.add("Center", textArea); frame.show(); } static synchronized void toFrame(String string) { if(active) textArea.appendText(string + '\n'); } static synchronized void toFrame(double num) { toFrame("" + num); } static synchronized void toFrame(Object object) { if(active) toFrame(object.toString()); } static synchronized void assert(String what, boolean isTrue) { if(active && !isTrue) textArea.appendText("Assertion \"" + what + "\" failed\n"); } static synchronized void on() { if(opened) active = true; } static synchronized void off() { active = false; } } class DebugFrame extends Frame { DebugFrame(String caption) { super(caption); } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) { hide(); dispose(); return true; } return super.handleEvent(evt); } }

167

Dodatek D

Styl programowania

Istnieje tyle stylw programowana ilu jest programistw. Jednak bez trudu mona stwierdzi, e jedne style s lepsze od innych. Dlatego, w celu ujednolicenia zapisu i tym samym uatwienia wymiany programw, podano tu opis stylu zasto sowanego w niniejszej ksice.

Wygld
Program zapisuje si czcionk rwnomiern, na przykad Courier. aden wiersz programu nie liczy wicej ni 60 znakw. W celu spenienia tych wymaga oraz zwikszenia czytelnoci kodu stosuje si amanie wierszy i dodawanie odstpw (spacji i pustych wierszy). amania wyrae dokonuje si w taki sposb, aby ostatnim znakiem zamanego wiersza by operator.
public static boolean draw(Graphics gDC, Color color, int x, int y, int width, int height) { StreamTokenizer tokens = new StreamTokenizer( "c:\\cafe" + "myfile.txt" ); // ... }

Konsekwencja
Identyczne konstrukcje jzyka zawsze wygldaj tak samo.
int arr[]; int[] vec; System.out.println(); System.out.print('\n'); // niekonsekwentnie

// niekonsekwentnie

Nadmiarowo
Nadmiarowo jest dozwolona tylko w celu zwikszenia czytelnoci programu. Dotyczy to w szczeglnoci: uycia zbdnego odnonika this, uycia zbdnych nawiasw oraz uycia zbdnych specyfikatorw.
class Square { int side; Square(int base) { this.side = base; // ... if((a > 0) && (a < 10)) System.exit(0); } // ... } abstract interface Discardable { static final int ZERO = 0; // ... }

// zbdne this // zbdne nawiasy

// zbdne abstract // zbdne static i final

Komentarze
Komentarz wierszowy jest wyrwnany w pionie wzgldem pozostaych takich komentarzy z jego otoczenia.
int x; int y; // xCen // yCen

168

Komentarz blokowy zapisuje si od pierwszej kolumny. W wierszach nastpnych zapisuje si dodatkowy znak * ( gwiazdka). Zakoczenie komentarza zapisuje si w osobnym wierszu. Og gwiazdek tworzy lini pionow.
/* Hello * from * me */

Uwaga: W dalszym opisie istnienie komentarzy nie bdzie brane pod uwag. W tym sensie za ostatni znak wiersza
int x; // xCen

bdzie odtd uznawany rednik.

Wcicia
Jeli pewna konstrukcja skadniowa zawiera inn (na przykad definicja klasy zawiera deklaracj metody), to konstrukcj wewntrzn wcina si wzgldem zewntrznej. Wcicie uzyskuje si przez wstawienie cigu spacji. Minimalny rozmiar wcicia: 4 spacje. Wszystkie wcicia musz by rwne. Znaku tabulacji nie uywa si.
class Greet { int fun(int a) { if(a < 0) return 0; return a * a; } }

Identyfikatory
Identyfikatory pakietw zaczynaj si od maej litery. Identyfikatory typw, staych i etykiet od duej. Identyfikatory pl, zmiennych i procedur od maej. Zaleca si dobieranie nazw mnemonicznych, na przykad getV i setV isV toV dla pobrania/zmiany (np. getColor, setColor) dla badania (np. isEmpty) dla konwersji (np. toString)

Nazwy jednoliterowe stosuje si tylko w specjalnych przypadkach, np. b c d e f i, j, k l o s v dla byte dla char dla double dla Exception dla float dla licznikw dla long dla Object dla String dla wartoci

W identyfikatorach wielosowowych stosuje si due litery, a nie znaki podkrelenia. Znaku podkrelenia uywa si tylko w identyfikatorach staych.
int index; void getArea(); public anyVeryLongMeaningfulName; public static final double Pi = 3.14; final Color COLOR_RED = Color.red;

Separatory
169

Po kadym przecinku, dwukropku i redniku wystpuje odstp (wyjtek: instrukcja for). Przed przecinkiem oraz rednikiem oraz po nawiasie otwierajcym i przed nawiasem zamykajcym nie stawia si odstpu (wyjtek: rednik w instrukcji for).
fun(a, fun(a, b), b); fun ( a , b ); fun(a, b); // zbdne odstepy // dobrze

Specyfikatory
Specyfikatory klas i interfejsw wymienia si w nastpujcej kolejnoci: dostpno (public, protected, private), abstrakcyjno (abstract), ustalono (final), rodzaj (class, interface). Specyfikatory procedur wymienia si w nastpujcej kolejnoci: dostpno (public, protected, private), statyczno (static), abstrakcyjno (abstract), rodzimo (native), ustalono (final), synchroniczno (synchronized), typ (void, int, itp.). Specyfikatory pl i zmiennych wymienia si w nastpujcej kolejnoci: dostpno (public, protected, private), statyczno (static), nietrwao (transient), ulotno (volatile), ustalono (final), typ (void, int, itp.).
public abstract class Input { protected static void fun(); public abstract synchronized int met(int x); private static volatile final int var = 12; // ... }

Bloki
Klamr otwierajc ciao klasy albo interfejsu oraz blok zawarty w innej instrukcji (np. w inicjatorze klasy) umieszcza si p o spacji, w tym samym wierszu co nagwek klasy albo interfesju, albo pocztkowa fraza instrukcji. W pozostaych przypadkach klamr otwierajc umieszcza si w osobnym wierszu (dotyczy to przede wszystkim klamry otwierajcej ciao funkcji). Klamr zamykajc blok zawsze umieszcza si w osobnym wierszu.
class Any { void fun() { while(true) { int i = 0; { // .. } } } }

Definicje klas i interfejsw


Sowo kluczowe class i interface umieszcza si od pierwszej kolumny wiersza. Jeli definicja jest poprzedzona specyfikatorami, to umieszcza si je od pierwszej kolumny poprzedniego wiersza.
public abstract class Greet { // ... }

Definicje procedur
Nagwek procedury umieszcza si na pocztku wiersza, z jednym wciciem. Klamr otwierajc ciao procedury umieszcza si w osobnym wierszu. W przypadku licznych parametrw dopuszcza si przeniesienia po przecinku, wcite do pierwszego parametru.
public class Point { Point(int x) { // ... } Point(int a, int b, int c,

170

int d, int e) { // ... } }

Etykiety
Etykieta zaczyna si w osobnym wierszu, poczwszy od tej samej kolumny, od ktrej zaczyna si nastpujca po niej instrukcja.
Again: while(a > 5) { // ... break Again; }

Wyraenia
Midzy pustymi nawiasami kwadratowymi i okrgymi, po obu stronac h kropki oraz po operatorze jednoargumentowym nie umieszcza si spacji. Po obu stronach operatora dwuargumentowego umieszcza si spacj.
int arr[]; int len = +arr.length() + 1;

Uwaga: Jeli argumentem operacji dwuargumentowej jest liczba, to zezwala si, aby operator nie by otoczony spacjami jeli zwikszy to czytelno programu.
arr[2*i+1] = 2*(i-1);

Wyraenie ktre nie mieci si w wierszu jest dzielone midzy kolejne wiersze w taki sposb, e ostatnim znakiem wiersza jest operator. Przeniesiona do nastpnego wiersza cz wyraenia jest wwczas wyrwnana albo wcita i wyrwnana.
System.out.println("Hello" + " " + "World"); System.out.println( "Hello" + " " + "World" );

Instrukcje
Kada instrukcja i podinstrukcja zaczyna si w osobnym wierszu.
if(a > 5) break; if(a > 5) break; // le

instrukcje if
Jeli po frazie if wystpuje klamra otwierajca, to odpowiadajc jej klamr zamykajc umieszcza si pod if. Jeli po frazie else wystpuje fraza if, to frazy else i if zapisuje si w tym samym wierszu. Jeli instrukcja if zawiera fraz fraz else, to kady z nastpujcych napisw
else } else } else {

umieszcza si w osobnym wierszu, w pionowym wyrwnaniu pod if.


if(a > 5) fun(a, b) if(a > 5) fun(a, b) else { fun(c, d);

171

fun(e, f); } if(a > 5) { fun(a, b); fun(c, d); } else { fun(e, f); return; } if(a > 5) fun(i); else if(b > 5) { fun(i+1); return; }

instrukcje for
Przed pierwszym rednikiem frazy zawartej w nagwku instrukcji for nie stawia si spacji. Po kadej stronie drugiego umieszcza si jedn spacj.
for(int i = 0; i < 5 ; i++) { fun(i); fun(i+1); }

instrukcje while
Jeli ciaem instrukcji while jest blok, to zamykajca go klamra wystpuje w pionowym wyrwnaniu pod while.
while(a > 5) { fun(i); fun(i+1); }

instrukcje do
Jeli ciaem instrukcji do jest blok, to otwierajca go klamra wystpuje w tym samym wierszu co nawias zamykajcy nagwek, a napis
} while(

wystpuje w pionowym wyrwnaniu pod do.


do { fun(i); fun(i+1); } while(i < 4);

instrukcje switch
Klamra otwierajca blok instrukcji switch wystpuje w tym samym wierszu co nagwek instrukcji. Kada fraza case zaczyna si i koczy w osobnym wierszu. Instrukcje frazy case s wzgldem niej wcite.
switch(a) { case 0: a = 3; break; case 1: a = 4; }

instrukcje try
Klamra otwierajca bloku try wystpuje w tym samym wierszu co sowo kluczowe try. Kada fraza catch zaczyna si od nowego wiersza.
try { fun(i); }

172

catch(IOException e) { } catch(Exception e) { System.out(e.getMessage()); } finally { i = 0; }

173

Dodatek E

Typy predefiniowane

Predefiniowanymi typami danych s typy orzecznikowe, arytmetyczne i acuchowe. Typy arytmetyczne dziel si na cakowite (byte, short, int, long), rzeczywiste (float, double) i znakowe (char). Typami acuchowymi s predefiniowane typy obiektowe: String i StringBuffer. Uwaga: Poniewa typ znakowy jest typem arytmetycznym, wic na jego danych mona wykonywa takie same operacje jak na danych cakowitych i rzeczywistych.

Typ orzecznikowy
Typem orzecznikowym jest typ " boolean". Zmienne typu orzecznikowego mog przybiera wartoci true (prawda) i false (fasz). Kade wyraenie orzecznikowe exp moe by poddane konwersji na wyraenie cakowite za pomoc operacji exp ? 1 : 0 (por. Dodatek Operacje i operatory), a kade wyraenie cakowite exp moe by poddane konwersji na wyraenie orzecznikowe za pomoc operacji exp != 0

Typy cakowite
Typami cakowitymi s: "byte", "short", "int" i "long". Zmienne typw cakowitych s byte short int long 8-bitowe 16-bitowe 32-bitowe 64-bitowe (od (od (od (od -128 do 127) -32768 do 32767) -2,147,483,648 do 2,147,483,647) -9,223,372,036,854,775,808 do +9,223,372,036,854,775,807)

Dane przypisane zmiennym cakowitym s reprezentowane w uzupenie do 2. Wynika std m.in., e jeli zaneguje si wszystkie bity danej, a nastpnie doda do niej 1, to skutek bdzie taki, jakby znak danej zmieniono na przeciwny. Typ liczby wynika jednoznacznie z jej wartoci (jako kryterium wyboru przyjmuje si oszczdno reprezentacji). Niezalenie od jej wartoci, liczba zakoczona liter L albo l jest typu "long". Na przykad 32767 jest typu "short", a 32768 jest typu "int", ale 0L jest typu "long".

Typy rzeczywiste
Typami rzeczywistymi s: "float" i "double". Zmienne typw cakowitych s: float double 32-bitowe (w przyblieniu od -3.4e38 do 3.4e38) 64-bitowe (w przyblieniu od -1.8e308 do 1.8e308)

Dane przypisane zmiennym rzeczywistym s reprezentowane w zapisie moduu-i-znaku, a wyniki nietypowych operacji, jak na przykad 1.0 / 0 1.0 /-0 1.0 / 0 * 0 (Double.POSITIVE_INFINITY) (Double.NEGATIVE_INFINITY) (Double.NaN tj. NotANumber)

maj wartoci, ktre mona reprezentowa przez symbole podane w nawiasach. Kada liczba z wskiego przedziau wok 0 jest reprezentowana przez zero-ze-znakiem (tj. ujemne-zero albo dodatnie-zero). Z punktu widzenia relacji rwne i nie-rwne oba te zera uznaje si za rwne. 174

Typ liczby rzeczywistej wynika jednoznacznie z jej wartoci (jako kryterium wyboru przyjmuje si oszczdno reprezentacji). Kada prosta liczba rzeczywista (np. -1.2, 1., -.2, 1.2e-1) oraz kada prosta liczba rzeczywista zakoczona liter D albo d jest typu "double". Kada prosta liczba cakowita albo rzeczywista zakoczona liter F albo f jest typu "float". Na przykad -2.4 oraz 3e2 jest typu "double", a -2e-3f jest typu "float".

Typ znakowy
Typem znakowym jest "char". Zmiennym typu znakowego s zazwyczaj przypisywane 16 -bitowe znaki Unikodu. Unikod umoliwia reprezentowanie znakw wszystkich jzykw europejskich oraz wikszoci znakw pozostaych jzykw, w tym ideograficznych znakw Han uywanych w krajach azjatyckich. Pierwszych 256 Unikodu jest identycznych ze znakami kodu ASCII Latin-1 (kod ten zawiera m.in. wikszo znakw jzykw zachodnio-europejskich). Literay typu "char" maj posta 'c' gdzie c jest: znakiem widocznym (np. 'a'), symbolem znaku (np. '\n'), semkowym kodem znaku (np. '\141') albo czterocyfrowym szesnastkowym kodem znaku (np. '\u0061').

Typy acuchowe
Predefiniowanymi typami acuchowymi s String i StringBuffer. W istocie nie s to odrbne typy, gdy zostay implementowane jako klasy obiektowe. Jednak ze wzgldu na szczegln rol jak peni w jzyku, zasuguj na specjalne potraktowanie. Zarwno String, jak i StringBuffer, s klasami ustalonymi (final), to jest takimi, ktre nie mog by dziedziczone. Waciwo ta zapewnia im bardzo efektywn implementacj. Obiekty klasy String s niemodyfikowalne, a wic, jeli rezultat pewnej operacji jest klasy String, to nie musi by odrbnym obiektem. Obiekty klasy StringBuffer s modyfikowalne. Klasa StringBuffer jest uywana przede wszystkim do tworzenia nowych obiektw klasy String. W szczeglnoci, wyraenie
4 + "sale"

jest niejawnie przeksztacane w wyraenie


new StringBuffer().append(4).append("sale").toString()

Klasa String
Metody klasy String s uywane do porwnywania, porzdkowania, rozpoznawania, wycinania i przeksztacania znakw. Uwaga: Znaki acuchw s indeksowane od 0. Jeli metoda ma zwrci indeks znaku, ale takiego znaku nie ma, to zwraca warto -1.
boolean equals(Object obj)

Metoda suy do porwnania acucha z obiektem przeksztaconym w acuch (najczciej z innym acuchem).
String hello = "Hello"; String world = "World"; boolean result = hello.equals(world);

// false

int compareTo(String string)

Metoda suy do porwnania dwch acuchw. Jeli s rwne, to rezultatem jest 0. Jeli pierwszy jest mniejszy, to rezultatem jest liczba ujemna, a jeli drugi, to dodatnia.
String hello = "Hello"; String world = "World";

175

int value = hello.compareTo(world); if(value < 0) text = "less"; else if(value == 0) text = "equal"; else text = "greater"; boolean result = text.equals("less");

// true

char charAt(int pos)

Metoda zwraca znak wystpujcy na podanej pozycji acucha.


String string = "Hello"; char chr = string.charAt(4); // 'o'

int indexOf(char chr)

Metoda zwraca indeks pierwszego wystpienia podanego znaku w acuchu.


String string = "buffer"; int result = string.indexOf('u'); //1

int indexOf(String string)

Metoda zwraca indeks pierwszego znaku stanowicego podany podcig acucha.


String string = "remaining"; int pos = string.indexOf("main"); // 2

String substring(int from, int to)

Metoda zwraca podcig acucha skadajcy si ze znakw wystpujcych "midzy" znakami o podanych indeksach.
String string = "0123456789"; String result = string.substring(2, 6); // 2345 (sic!)

String toUpperCase(String string)

Metoda zwraca acuch powstay z oryginau przez zamian kadej maej litery na du.
String string = "Hello"; String result = string.toUpperCase(); // HELLO

String toLowerCase(String string)

Metoda zwraca acuch powstay z oryginau przez zamian kadej duej litery na ma.
String string = "Hello World"; String result = string.toLowerCase(); // hello world

Klasa StringBuffer
Metody klasy StringBuffer s uywane do przeksztacania cigw znakw. W odrnieniu od metod klasy String, metody te na og nie tworz nowych obiektw, ale tylko modyfikuj je.
void setCharAt(int index, char chr)

Metoda zmienia znak na podanej pozycji acucha.


StringBuffer string = new StringBuffer("Hello World"); string.setCharAt(5, '*'); String result = new String(string); // Hello*World

StringBuffer append(char chr)

Metoda wydua acuch o podany znak. 176

StringBuffer string = new StringBuffer("Hello"); string.append('*').append("World"); String result = new String(string); // Hello*World

StringBuffer append(String string)

Metoda wydua acuch o podany acuch.


StringBuffer string = new StringBuffer("Hello"); string.append("World"); String result = new String(string); // HelloWorld

StringBuffer append(char arr[], int offset, int len)

Metoda wydua acuch o znaki podanego wycinka tablicy.


char arr[] = { ' ', 'W', 'o', 'r', 'l', 'd' }; StringBuffer string = new StringBuffer("Hello"); string.append(arr, 1, 5); String result = new String(string); // HelloWorld

StringBuffer append(Object obj)

Metoda wydua acuch o acuch utworzony z podanego obiektu, po wywoaniu na jego rzecz metody toString jego klasy.
Double value = new Double(2 - 3.4); StringBuffer string = new StringBuffer("x"); string.append(value); String result = new String(string); // x-1.4

StringBuffer insert(int offset, char chr)

Metoda wstawia podany znak w podanym miejscu acucha.


StringBuffer string = new StringBuffer("HelloWorld"); string.insert(5, '*'); String result = new String(string); // Hello*World"

StringBuffer insert(int offset, String string)

Metoda wstawia podany acuch w podanym miejscu acucha.


StringBuffer string = new StringBuffer("HelloWorld"); string.insert(5, "***"); String result = new String(string); // Hello***World"

StringBuffer insert(int offset, char arr[])

Metoda wstawia znaki tablicy w podanym miejscu acucha.


char arr[] = { '*', ' ', '*' }; StringBuffer string = new StringBuffer("HelloWorld"); string.insert(5, arr); String result = new String(string); // Hello* *World"

StringBuffer insert(int offset, Object obj)

Metoda wstawia znaki acucha utworzonego z podanego obiektu, po wywoaniu n a jego rzecz metody toString jego klasy.
Integer value = new Integer(2); StringBuffer string = new StringBuffer("x"); string.insert(0, value); String result = new String(string); // 2x

Typy kopertowe

177

Typami kopertowymi s predefiniowane typy obiekto we "Boolean", "Integer", "Long", "Float", "Double", "Character. Obiekt typu kopertowego stanowi otoczk dla zmiennej odpowiadajcego mu typu podstawowego: " boolean", "int", "long", "float", "double", "char". Na zmiennych typu kopertowego mona wykonywa wiele operacji, ktrych nie mona wykonywa na zmiennych typu podstawowego. W szczeglnoci, zmienne typu kopertowego mona tworzy na stercie, a za pomoc funkcji ich typu mona dokonywa wielu uytecznych konwersji, podanych tu dla typu " Integer".
public static Integer valueOf(String str)

Rezultatem funkcji jest zmienna typu kopertowego zainicjowana wartoci liczby zawartej w podanym acuchu.
Integer var(0); var = Integer.valueOf("20"); System.out.print(var);

// 20

public static String toString(int val)

Rezultatem funkcji jest odnonik do obiektu zainicjowanego acuchem utworzonym z argumentu.


int var = 20; String str = var.toString(); System.out.print(str);

// 20

public static int parseInt(String str)

Rezultatem funkcji jest zmienna typu podstawowego zainicjowana wartoci liczby zawartej w podanym acuchu.
int val = Integer.parseInt(str);

178

Dodatek F

Operacje i operatory

Opisem operacji jakie maj by wykonane na danych jest wyraenie. O kolejnoci wykonania operacji wchodzcych w skad wyraenia decyduje sposb uycia nawiasw oraz uwzgldnienie priorytetw i wiza operatorw (por. Dodatek Priorytety operatorw). We wszystkich pozostaych przypadkach wyraenia s opracowywane cile od-lewej-do-prawej (dotyczy to w szczeglnoci kolejnoci opracowywania argumentw procedur).

Wyraenia stae
W niektrych miejscach programu (na przykad w wyraeniach fraz case), moe wystpi tylko wyraenie stae cakowite. W skad takiego wyraenia mog wchodzi jedynie literay, identyfikatory statycznych zmiennych ustalonych zainicjowanych wyraeniami staymi oraz konwersje do typu cakowitego. Na przykad
class Any { static final int one = 1; static final double two = 2.9; void sub(int par) { switch(par) { case one: // ... case (int)(two + 2): break; } } }

Wyraenie
(int)(two + 2)

jest wyraeniem staym o wartoci 4 (sic!).

Respektowanie nawiasw
Jeli wyraenie w nawiasach okrgych jest poprzedzone operatorem, to wykonanie operacji okrelonej przez ten operator nastp i dopiero po opracowaniu wyraenia w nawiasach. Na przykad
a - (b + c)

Operacja odejmowania zostanie wykonana dopiero po wykonaniu operacji dodawania.

Uwzgldnianie priorytetw
Jeli wyraenie jest argumentem dwch operatorw o rnym priorytecie, to najpierw wykonuje si operacj okrelon przez operator o wyszym priorytecie. Na przykad
a + b * c; // a + (b * c);

Najpierw zostanie wykonana operacja mnoenia, a dopiero po niej operacja dodawania.

Uwzgldnianie wiza
179

Jeli wyraenie moe by uznane za argument dwch operatorw o rwnym priorytecie, to kolejno wykonania operacji jest okrelona przez wizanie. Jeli wizanie operatora jest lewe, to najpierw jest wykonywana operacja okrelona przez operator znajdujcy si z lewej strony wyraenia, a jeli jest prawe, to najpierw z prawej strony. Na przykad
double num; int fix; num = fix = 4;

Poniewa operator przypisania ma wizanie prawe, wic ostatnia instrukcja jest traktowana tak jak instrukcja
num = (fix = 4);

a ta jak para instrukcji


fix = 4; num = fix;

Realizowanie skutkw ubocznych


Skutkiem ubocznym opracowania wyraenia jest wykonanie przypisa i przesa danych. Skutek uboczny operacji musi by zrealizowany nie pniej ni w najbliszym punkcie charakterystycznym. Punkt charakterystyczny programu wystpuje tu za kadym kompletnym wyraeniem i deklaratorem, tu po operatorach && (koniunkcja), || (dysjunkcja) oraz tu po znaku ? (pytajnik) w trjargumentowym operatorze ?:. Na przykad
int fix = 0; boolean bool = fix++ != 0 || fix != 0;

W chwili opracowywania prawego argumentu operatora dysjunkcji zmienna fix ma warto 1. Gdyby przed tym operatorem nie wystpowa punkt charakterystyczny, to mogaby mie warto 0. _________________________________________________________________________________________

Operacje
Operacje na danych mog by wykonywane za pomoc wyrae fabrykujcych, albo za pomoc operatorw. Poniewa napisy [] (nawias, nawias), . (kropka), () (nawias, nawias) i new nie s operatorami, wic indeksowania tablicy, wybierania skadnikw klasy, wywoywania procedur oraz zarzdzania pamici operacyjn nie realizuje si za pomoc operatorw.

Indeksowanie tablicy
Indeksowanie tablicy wyraa si za pomoc znakw [] (nawias, nawias). Rezultatem indeksowania jest element tablicy. Wizanie indeksowania tablicy jest lewe.
Np. arr[10][20] == (arr[10])[20]

Operacja indeksowania ma posta


ref[ind]

w ktrej ref jest odnonikiem do tablicy, a ind jest wyraeniem cakowitym. Wyraenie ref[ind] jest l-nazw tego elementu tablicy identyfikowanej przez ref, ktry ma indeks ind. 180

Na przykad
int vec[] = { 10, 20, 30 };

Zmienna vec jest odnonikiem do 3-elementowego wektora. Wyraenie vec[0] jest nazw pierwszego, a wyraenie vec[2] jest nazw ostatniego elementu tego wektora.

Wybr skadnika
Wybr skadnika klasy wyraa si za pomoc znaku . (kropka). Rezultat wyboru pola jest zmienn opisan przez to pole. Wizanie wyboru skadnika jest lewe.
Np. var.fun().var == (var.fun()).var

Operacja wyboru ma posta


ref.name

w ktrej ref jest odnonikiem do obiektu, a name jest identyfikatorem jego skadnika. Wyraenie ref.name jest l-nazw skadnika obiektu identyfikowanego przez ref. Na przykad
class Child { String name; int age = 0; Child(String name, int age) { this.name = name; this.age = age; } void setAge(int name) { this.age = age; } void sub() { Child tom = new Child("Thomas", 12), bob = new Child("Robert", 0) ; // ... System.out.println(tom.name); bob.setAge(12); // ... } }

Wywoanie procedury
Wywoanie procedury wyraa si za pomoc znakw () (nawias, nawias). Jeli typ procedury jest rny od " void", to istnieje jej rezultat.
Np. sub(x, y).z = 2;

Operacja wywoania procedury ma posta


ref.proc(arg, arg, ... , arg)

w ktrej ref jest odnonikiem identyfikujcym obiekt klasy, zawierajcej procedur proc, a kade arg jest argumentem wywoania. Rezultatem wywoania procedury typu rnego od "void" jest zmienna zainicjowana wartoci okrelon w instrukcji powrotu. Na przykad
class Master { int fix;

181

Master met() { return new Master(); } void sub() { met().fix = 12; met() = null; // bd (met() nie jest l-nazw) } }

Typ rezultatu metody met jest odnonikowy. Wywoanie met() jest nazw zmiennej, ale nie jest l-nazw.

Zarzdzanie pamici operacyjn


Zarzdzanie pamici operacyjn odbywa si za pomoc operacji new. Wykonanie operacji new powoduje przydzielenie obszaru pamici na stercie. Zwolnienie obszaru dokona si automatycznie, ale nie wczeniej ni po tym, gdy ani jeden odnonik nie bdzie ju identyfikowa tego obszaru.

Przydzielenie obiektu
Operacja przydzielenia obiektu ma posta
new Class(arg, arg, ... , arg)

w ktrej Class jest nazw klasy, a kade arg jest argumentem jej konstruktora. Rezultatem operacji przydzielenia jest odnonik do wanie przydzielonego obiektu. Na przykad
String ref = new String("Hello"); ref = new String();

Przydzielenie tablicy
Operacja przydzielenia tablicy ma posta
new Type [exp][exp] ... [exp]

w ktrej Type jest identyfikatorem typu (np. " int" albo "String"), a kade exp jest wyraeniem cakowitym (jeli pewne z nich jest puste, to wszystkie nastpujce po nim take musz by puste). Rezultatem operacji przydzielenia tablicy jest odnonik do wanie przydzielonej tablicy. Na przykad
int vec[] = new int [2]; vec = new int [4]; String arr[][] = new String [3][]; arr = new String [3][4];

Po wykonaniu instrukcji
int vec[] = new int [2];

odnonik vec identyfikuje 4-elementow tablic zmiennych typu " int". Po wykonaniu instrukcji
String arr[][] = new String [3][];

odnonik arr identyfikuje 3-elementow tablic odnonikw do tablic odnonikw do obiektw klasy String (kady z 3 odnonikw tablicy ma warto null). 182

Po wykonaniu instrukcji
arr = new String [3][4];

odnonik arr identyfikuje 3-elementow tablic odnonikw do 4-elementowych tablic odnonikw do obiektw klasy String (kady z 3 odnonikw ma warto rn od null, ale kady z pozostaych ma warto null).

_______________________________________________________________________________________

Operatory
Wykaz operatorw jzyka, z podaniem ich priorytetw i wiza znajduje si w Dodatku Priorytety operatorw. Rezultatem kadej z wymienionych tu operacji jest zmienna. Kade wyraenie okrelone przez operacj jest chwilow nazw tej zmiennej. To, czy jest l-nazw wynika z opisu operacji.

Operatory konwersji
Operatorem konwersji jest (Type). Wizanie operatora konwersji jest prawe.
Np. (double)(int)12.8 == (double)((int)12.8)

Operacja konwersji ma posta


(Type)exp

w ktrej Type jest nazw typu docelowego, a exp jest wyraeniem poddawanym konwersji. Rezultatem konwersji jest zmienna typu " Type", zainicjowana wartoci wyraenia exp po przeksztaceniu jej do typu " Type". Uwaga: Jeli typem docelowym jest tablica odnonikw, to w nazwie typu nie mog wystpi rozmiary tablicy. Na przykad
String str[] = { "Hello", "World" }; Object obj[] = (Object [])str; System.out.print((String)obj[0]); system.out.print(obj[1]);

// Hello // World

Konwersje nieodnonikowe
Rezultatem konwersji nieodnonikowej (np. z typu " double" do "int") jest zmienna typu "Type", zainicjowana wartoci wyraenia exp po przeksztaceniu jej do typu " Type". Na przykad
System.out.print(12.8); System.out.print((double)(int)12.8); // 12.8 // 12

Konwersje odnonikowe
Konwersja odnonikowa jest poprawna tylko wwczas, gdy jest dopuszczalna i wykonalna. Rezultatem poprawnej konwersji odnonikowej (np. z typu " Vector" do "Object") jest odnonik zainicjowany wartoci argumentu. Konwersja odnonikowa jest dopuszczalna tylko wwczas, gdy jest tosamociowa (np. z typu " Vector" do "Vector") albo gdy polega na przeksztaceniu z klasy do nadklasy (np. z " Vector" do "Object"), z klasy do podklasy (np. z "Object" do "Vector") albo z klasy do implementowanego przez ni interfejsu (np. z " Vector" do "Cloneable"). Konwersja odnonikowa jest wykonalna tylko wwczas, gdy jest dopuszczalna, a wyraenie
exp instanceof Type

183

(por. opis operatora instanceof) ma warto true. Na przykad


String Object city = Vector city = "Warsaw"; obj = city; (String)obj; vec = (Vector)obj; // konwersja niejawna // konwersja jawna // bd (konwersja niewykonalna)

Operatory zwikszenia i zmniejszenia


Operatorem zwikszenia jest ++ (plus, plus), a operatorem zmniejszenia jest --(minus, minus). Kady z nich moe wystpi w postaci przyrostkowej albo przedrostkowej. Wizanie operatora przyrostkowego jest lewe, a przedrostkowego prawe. Argument operacji zwikszenia i zmniejszenia musi by l-nazw zmiennej.
Np. fix-++++fix == ++(++fix) // bd (++fix nie jest l-nazw)

Operacje przyrostkowe
Przyrostkowa operacja zwikszenia ma posta
var++

a przyrostkowa operacja zmniejszenia ma posta


var--

w ktrych var jest wyraeniem arytmetycznym (m.in. typu "char"). Wyraenie var++ jest nazw zmiennej tymczasowej zainicjowanej wyraeniem var. Skutkiem ubocznym wykonania operacji jest zwikszenie wartoci zmiennej var o 1. Wyraenie var-- jest nazw zmiennej zainicjowanej wyraeniem var. Skutkiem ubocznym wykonania operacji jest zmniejszenie wartoci zmiennej var o 1. Na przykad
int fix = 12; int fix1 = fix--; System.out.print(fix); System.out.print(fix1);

// 11 // 12

Operacje przedrostkowe
Przedrostkowa operacja zwikszenia ma posta
++var

a przedrostkowa operacja zmniejszenia ma posta


--var

w ktrych var jest wyraeniem arytmetycznym (m.in. typu "char"). Wyraenie ++var jest l-nazw zmiennej var. Skutkiem ubocznym wykonania operacji jest zwikszenie wartoci zmiennej var o 1. Wyraenie --var jest l-nazw zmiennej var. Skutkiem ubocznym wykonania operacji jest zmniejszenie wartoci zmiennej var o 1. Na przykad 184

int fix = 10; int fix1 = ++fix; System.out.print(fix); System.out.print(fix1);

// 11 // 11

Operatory zachowania i zmiany znaku


Operatorami zachowania i zmiany znaku s + (plus) i - (minus). Wizanie tych operatorw jest prawe.
Np. -+var == -(+var)

Operacja zachowania znaku ma posta


+exp

a operacja zmiany znaku ma posta


-exp

w ktrych exp jest wyraeniem arytmetycznym. Wyraenie +exp oraz wyraenie -exp jest nazw zmiennej takiego samego typu jakiego jest wyraenie exp, ale po poddaniu go promocjom (np. z typu "char" do "int"). Na przykad
char fix = '2'; System.out.print(fix); System.out.print(+fix); // 2 // 50 (kod cyfry 2)

Operatory czynnikowe
Operatorami czynnikowymi s * (gwiazdka), / (skonik) i % (procent). Operatory czynnikowe s uywane w operacjach mnoenia, dzielenia i wyznaczania reszty z dzielenia. Wizanie operatorw czynnikowych jest lewe.
Np. a / b * c == (a / b) * c

Operator *
Operacja mnoenia ma posta
expL * expR

w ktrej expL i expR s wyraeniami arytmetycznymi. Rezultat mnoenia jest nazw zmiennej, zainicjowanej iloczynem argumentw. Na przykad
System.out.print('#' * 2); // 70

Operator /
Operacja dzielenia ma posta
expL / expR

w ktrej expL i expR s wyraeniami arytmetycznymi. Rezultat dzielenia jest nazw tymczasowej zmiennej, zainicjowanej ilorazem lewego i prawego argumentu. Jeli oba argumenty s cakowite, to rezultat take jest cakowity. 185

Na przykad
System.out.print(5.0 / 2); System.out.print(5 / 2); System.out.print(1 / 2 * 4); System.out.print(1. / 2 * 4); // // // // 2.5 2 0 2

Operator %
Operacja wyznaczenia reszty z dzielenia ma posta
expL % expR

w ktrej expL i expR s wyraeniami arytmetycznymi cakowitymi. Rezultat wyznaczenia reszty jest nazw zmiennej zainicjowanej reszt z dzielenia lewego argumentu przez prawy. Znak reszty jest taki sam jak znak lewego argumentu. Przyjmuje si z definicji, e
a % b == a - (a / b) * b

Na przykad
System.out.print(14 % 3); System.out.print(14 % -3); System.out.print(-14 % 3); // 2 // 2 // -2

Operatory skadnikowe
Operatorami skadnikowymi s + (plus) i - (minus). Operatory skadnikowe s uywane w operacjach dodawania i odejmowania. Wizanie operatorw skadnikowych jest lewe.
Np. a - b - c == (a - b) - c

Operator +
Operacja dodawania ma posta
expL + expR

w ktrej expL i expR s wyraeniami arytmetycznymi, znakowymi albo acuchowymi. Rezultat dodawania jest nazw zmiennej, zainicjowanej sum argumentw. Na przykad
System.out.print(2 + System.out.print('#' System.out.print('a' System.out.print('a' 3); + 1); + 0); + "0"); // // // // 5 36 97 a0

Operator Operacja odejmowania ma posta


expL - expR

w ktrej expL i expR s wyraeniami arytmetycznymi. Rezultat odejmowania jest nazw zmiennej, zainicjowanej rnic lewego i prawego argumentu. Na przykad 186

System.out.print(2 - 3); System.out.print('z' - 'a');

// -1 // 25

Operator pochodzenia
Operatorem pochodzenia jest instanceof. Wizanie operatora przynalenoci jest lewe.
Np. ((Object)new String()) instanceof String

Operacja pochodzenia ma posta


exp instanceof Class

w ktrej exp jest wyraeniem odnonikowym, a Class jest identyfikatorem klasy. Rezultatem operacji pochodzenia jest orzecznik, ktry ma wartoc true tylko wwczas, gdy odnonik exp identyfikuje obiekt klasy Class albo jej podklasy. Na przykad
class Person { // ... } class Woman extends Person { // ... } class Master { static void sub(Person person) { if(person instanceof Woman) { Woman woman = (Woman)person; // ... } } }

Instrukcja
Woman woman = (Woman)person;

zostanie wykonana tylko wwczas, gdy odnonik person identyfikuje obiekt klasy Woman. Tak si stanie, gdy funkcja sub zostanie wywoana za pomoc instrukcji
Master.sub(new Woman());

ale nie stanie si, jeli zostanie wywoana za pomoc instrukcji


Master.sub(new Person());

Operatory porwnania
Operatorami porwnania s: < (mniejsze), > (wiksze), <= (mniejsze, rwne), >= (wiksze, rwne), == (rwne), != (nie rwne). Dwa ostatnie operatory maj priorytet niszy ni pozostae. Wizanie operatorw porwnania jest lewe.
Np. a < b < c == (a < b) < c

Operacja porwnania ma posta


expL @ expR

187

w ktrej @ jest dowolnym operatorem porwnania, a expL i expR s wyraeniami: oba arytmetycznymi, oba orzecznikowymi, albo oba odnonikowymi. Rezultatem operacji porwnania jest zmienna orzecznikowa o wartoci true jeli relacja okrelona przez porwnanie jest prawdziwa, albo zmienna o wartoci false jeli relacja jest faszywa.

Porwnania arytmetyczne
Porwnanie zmiennych arytmetycznych (w tym zmiennych typu " char") polega na porwnaniu ich wartoci liczbowych. Na przykad
System.out.print(1.2 >= 1); // true

Porwnania orzecznikowe
Porwnanie zmiennych orzecznikowych polega na porwnaniu ich wartoci logicznych. Zezwala si na uycie tylko operatorw rwne (==) i nie-rwne (!=). Na przykad
boolean flag = true; System.out.print(flag != false); // true

Porwnania odnonikowe
Porwnania odnonikw mog by tylko na rwno (==) i nie-rwno (!=). Jeli oba odnoniki identyfikuj ten sam obiekt (w szczeglnoci tablic), to rezultat porwnania na rwno ma warto true, a w przeciwnym razie ma warto false. Analogicznie definiuje si porwnanie na nie-rwno. Na przykad
String one = "Hello" + "World", two = "HelloWorld"; System.out.print(one == two); System.out.print(one + "" != one);

// true // true

Operatory logiczne
Operatorami logicznymi s: ! (zaprzeczenie), && (koniunkcja) i || (dysjunkcja). Najwyszy priorytet ma zaprzeczenie, a najniszy dysjunkcja. Wizanie operatora zaprzeczenia jest prawe, a pozostaych operatorw lewe.
Np. a || !b && c == a || ((!b) && c)

Operator !
Operacja zaprzeczenia ma posta
!exp

w ktrej exp jest wyraeniem orzecznikowym. Rezultatem operacji zaprzeczenia jest zmienna orzecznikowa. Zmienna ta ma warto true tylko wwczas, gdy wyraenie ma warto false. Na przykad
boolean flag = true; System.out.print(!flag); System.out.print(!(12 > 3); // false // false

188

Operator &&
Operacja koniunkcji ma posta
expL && expR

w ktrej expL i expR s dowolnymi wyraeniami orzecznikowymi. Rezultatem koniunkcji jest zmienna orzecznikowa. Zmienna ta ma warto true tylko wwczas, gdy oba wyraenia maj warto true. Uwaga: Tu przed operatorem && wystpuje punkt charakterystyczny. Jeli wyraenie expL ma warto false, to rezultat koniunkcji jest znany, a wic nie opracowuje si wyraenia expR. Na przykad
int vec[] = { 10, 20, 30 }; int chr = System.in.read(); boolean flag = chr >= '0' && chr <= '2'; if(flag && chr == vec[chr - 'a']) System.out.println();

Operacja == jest wykonywana tylko wwczas, gdy zmienna flag ma warto true.

Operator ||
Operacja dysjunkcji ma posta
expL || expR

w ktrej expL i expR s dowolnymi wyraeniami orzecznikowymi. Rezultatem dysjunkcji jest zmienna orzecznikowa. Zmienna ta ma warto false tylko wwczas, gdy oba wyraenia maj warto false. Uwaga: Tu przed operatorem || wystpuje punkt charakterystyczny. Jeli wyraenie expL ma warto true, to rezultat dysjunkcji jest znany, a wic nie opracowuje si wyraenia expR. Na przykad
int vec[] = { 10, 20, 30 }; int chr = System.in.read(); boolean flag = chr < '0' && chr > '2'; if(flag || chr == vec[chr - 'a']) System.out.println();

Operacja == jest wykonywana tylko wwczas, gdy zmienna flag ma warto false.

Operatory bitowe
Operatorami bitowymi s: ~ (zanegowanie bitw), & (iloczyn bitw), | (suma bitw), ^ (suma modulo 2 bitw), << (przesunicie bitw w lewo), >> (przesunicie bitw w prawo), >>> (przesunicie bitw w prawo-bez-znaku). Najwyszy priorytet ma zanegowanie, niszy przesunicia, a potem kolejno: iloczyn, suma modulo 2 i suma. Wizanie operatora zanegowania bitw jest prawe, a pozostaych lewe.
Np. a || !b && c << d == a || ((!b) && (c << d))

Operator ~
Operacja zanegowania bitw ma posta
~exp

189

w ktrej exp jest wyraeniem cakowitym. Rezultatem operacji zanegowania bitw jest zmienna takiego samego typu jak exp, po poddaniu jej promocjom, a nastpnie zanegowaniu kadego jej bitu. Uwaga: Negacj bitu 1 jest bit 0, a negacj bitu 0 jest bit 1. Na przykad
int red = 1, green = 2, blue = 4; int hue = red | green; // 00 ... 011 (kolor ty) hue = ~hue; // 11 ... 100 (kolor niebieski)

Trzy najmniej znaczce bity zmiennej hue reprezentuj jeden z 8 kolorw. Wykonanie operacji zanegowania bitw powoduje zmian koloru na dopeniajcy.

Operator &
Operacja iloczynu bitw ma posta
expL & expR

w ktrej expL i expR s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienne expL i expR poddaje si konwersjom do typu wsplnego, a nastpnie kady bit wyniku tworzy si z odpowiadajcych sobie bitw argumentw wyznaczajc ich iloczyn logiczny. Uwaga: Iloczyn logiczny pary bitw ma warto 1 tylko wwczas gdy oba bity s jedynkowe. Na przykad
int fix = 6; int mask = '\u0003'; fix = fix & ~mask; System.out.print(fix); // // 00 ... 110 00 ... 011

// 4 (00 ... 100)

Wykonanie operacji na zmiennej fix powoduje wyzerowanie tych wszystkich jej bitw, ktre w masce mask s jedynkowe.

Operator ^
Operacja sumy modulo 2 bitw ma posta
expL ^ expR

w ktrej expL i expR s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienne expL i expR poddaje si konwersjom do typu wsplnego, a nastpnie kady bit wyniku tworzy si z odpowiadajcych sobie bitw argumentw wyznaczajc ich sum logiczn modulo 2. Uwaga: Suma logiczna modulo 2 pary bitw ma warto 1 tylko wwczas gdy bity s rne. Na przykad
int fix = 6; int mask = '\u0003'; fix = fix ^ mask; System.out.print(fix); // // 00 ... 110 00 ... 011

// 5 (00 ... 101)

Wykonanie operacji na zmiennej fix powoduje zanegowanie tych wszystkich jej bitw, ktre w masce mask s jedynkowe.

Operator |
190

Operacja sumy bitw ma posta


expL | expR

w ktrej expL i expR s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienne expL i expR poddaje si konwersjom do typu wsplnego, a nastpnie kady bit wyniku tworzy si z odpowiadajcych sobie bitw argumentw wyznaczajc ich sum logiczn. Uwaga: Suma logiczna pary bitw ma warto 0 tylko wwczas gdy oba bity s zerowe. Na przykad
int fix = 5; int mask = '\u0003'; fix = fix | mask; System.out.print(fix); // // 00 ... 101 00 ... 011

// 7 (00 ... 111)

Wykonanie operacji na zmiennej fix powoduje ustawienie tych wszystkich jej bitw, ktre w masce mask s jedynkowe.

Operator <<
Operacja przesunicia bitw w lewo ma posta
expL << N

w ktrej expL i N s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienn expL poddaje si promocji, a nastpnie kady bit wyniku tworzy si z bitw tej nowej zmiennej po przesuniciu ich o N pozycji w lewo. Uwaga: Podczas przesuwania w lewo bity najbardziej znaczce s odrzucane, a na pozycje najmniej znaczce wchodz bity 0. Na przykad
int fix = 7; fix = fix << 2; System.out.print(fix); // 00 ... 0111 // 28 (00 ... 011100)

Bity zmiennej fix przesunito o 2 pozycje w lewo.

Operator >>
Operacja przesunicia bitw w prawo ma posta
expL >> N

w ktrej expL i N s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienn expL poddaje si promocji, a nastpnie kady bit wyniku tworzy si z bitw tej nowej zmiennej po przesuniciu ich o N pozycji w prawo. Uwaga: Podczas przesuwania w prawo bity najmniej znaczce s odrzucane, a bit najbardziej znaczcy nie ulega zmianie. Na przykad
int fix = 15; fix = fix >> 2; System.out.print(fix); // 00 ... 01111

// 3 (00 ... 00011)

Bity zmiennej fix przesunito o 2 pozycje w prawo.

191

Operator >>>
Operacja przesunicia bitw w-prawo-bez-znaku ma posta
expL >>> N

w ktrej expL i N s wyraeniami cakowitymi. W celu utworzenia wyniku operacji, zmienn expL poddaje si promocji, a nastpnie kady bit wyniku tworzy si z bitw tej nowej zmiennej po przesuniciu ich o N pozycji w prawo. Uwaga: Podczas przesuwania w prawo bity najmniej znaczce s odrzucane, a bit najbardziej znaczcy jest zerowany. Na przykad
int fix = -1; fix = fix >>> 30; System.out.print(fix); // 111 ... 111

//3 (000 ... 011)

Bity zmiennej fix przesunito o 2 pozycje w prawo.

Operatory warunku
Operatorem warunku jest ?: (pytajnik, dwukropek). Wizanie operatora warunku jest prawe.
Np. a ? b : c ? d : e == a ? b : (c ? d : e)

Operacja warunku ma posta


exp ? expT : expF

w ktrej exp jest wyraeniem orzecznikowym, a expT i expF s wyraeniami dowolnego typu. Uwaga: Bezporednio za pytajnikiem wystpuje punkt charakterystyczny. Wyraenie warunkowe jest nazw zmiennej typu wsplnego "Type" wyrae expT i expF o wartoci (Type)expT dla exp o wartoci true (Type)expF dla exp o wartoci false Uwaga: W kadym przypadku jest opracowywane wyraenie exp oraz co dokadnie jedno z wyrae expT i expF. Na przykad
int fix, fix1 = 10, fix2 = 20; fix = System.in.read(); fix = (fix > 0 ? fix1 : fix2); fix = fix > 0 ? fix1 : fix2; System.out.print(fix); (fix > 0 ? fix1 : fix2) = 4;

// identyczne z poprzednim // 10 (sic!) // bd (wymagana l-nazwa)

Operatory przypisania
Operatorem przypisania jest = (rwna si) oraz kady operator o postaci @= w ktrej @ jest jednym z nastpujcych operatorw
* / % + << >> ^ & |

Wizanie operacji przypisania jest prawe.


Np. a = b += c == a = (b += c)

Operator =
192

Prosta operacja przypisania ma posta


var = exp

w ktrej var jest l-nazw zmiennej, a exp jest wyraeniem. Na przykad


int fix = 10; fix = 20; ++(fix = 20); // zainicjowanie // przypisanie // bd (fix = 20 nie jest l-nazw)

Jeli var jest typu arytmetycznego, to exp musi by typu arytmetycznego. Jeli jest typu odnonikowego Class, to wyraenie exp musi identyfikowa obiekt klasy Class albo jej podklasy. Wykonanie prostej operacji prz ypisania skada si z wyznaczenia wartoci wyraenia exp, poddania jej ewentualnej konwersji do typu zmiennej var, a nastpnie przypisania zmiennej var. Uwaga: Jeli typ wyraenia exp jest rny od typu zmiennej var, to wymaga si, aby konwersja moga by wykonana niejawnie. Na przykad
int fix; fix = 12; fix = (int)4.8; fix = 4.8; String name = "Isabel"; Object obj; obj = name; name = (String)obj; name = obj;

// bd (brak konwersji) // obj = (Object)name; // bd (brak konwersji)

Operatory @=
Rozszerzona operacja przypisania ma posta
var @= exp

Jest ona rwnowana operacji


var = var @ exp

ale tylko wwczas gdy opracowanie wyraenia var jest jednokrotne. Na przykad
int arr[] = { 10, 20 }, fix = 0; arr[fix += 1] += 3; // fix = fix + 1; arr[1] = arr[1] + 3; System.out.print(fix); // 1

Instrukcja
arr[fix += 1] += 3; // zwikszenie fix o 1

jest wykonywana tak jak


fix += 1; arr[fix] = arr[fix] + 3;

a wic nie jest rwnowana instrukcji


arr[fix += 1] = arr[fix += 1] + 3; // zwikszenie fix o 2

193

You might also like