Java - Podstawy, Programowanie, Zastosowania.pdf

(420 KB) Pobierz
untitled
Język Java: Podstawy, Programowanie, Zastosowania
Java
3
1. Język Java
Początki języka Java sięgają roku 1990, gdy Bill Joy napisał dokument pod tytułem “Further”, w
którym sugerował inżynierom Sun Microsystems stworzenie obiektowego środowiska w oparciu o
C++. Dokument ten miał pewien wpływ na twórców projektu Green (James Gosling, Patrick
Naughton i Mike Sheridan). W roku 1991 w ramach projektu Green opracowano w języku C
kompilator oraz interpretator wynalezionego przez Goslinga języka OAK (Object Application Kernel),
który miał być narzędziem do oprogramowania “inteligentnych” konsumenckich urządzeń
elektronicznych. Ponieważ nazwa “OAK” okazała się zastrzeżona, zmieniono ją na “Java”.
Obecnie należy raczej mówić o środowisku Java, na które składa się:
1. Obiektowy język Java, którego składnia wykazuje znaczne podobieństwo do składni języka C++.
Nazwa pliku z programem źródłowym w języku Java, ma postać “nazwa.java”, gdzie “nazwa”
musi być nazwą zdefiniowanej w tym pliku klasy. Jeżeli plik “nazwa.java” zawiera definicje wielu
klas, a wśród nich jedną klasę publiczną, to “nazwa” musi być nazwą tej klasy publicznej.
2. Kompilator, który przetwarza program “nazwa.java” na tak zwany B-kod (bytecode, J-code),
zapisywany automatycznie w plikach z rozszerzeniem nazwy “.class”. B-kod jest przenośną
postacią programu, która może być zinterpretowana przez odpowiednią maszynę wirtualną, to jest
“urządzenie logiczne”, na którym będzie wykonywany program binarny.
3. Specyfikacje maszyny wirtualnej Java (JVM – Java Virtual Machine) i plików klas. JVM można
uważać za abstrakcyjny komputer, który wykonuje programy, zapisane w plikach z rozszerzeniem
nazwy “.class”. Maszyna wirtualna może być implementowana na rzeczywistych komputerach na
wiele sposobów, na przykład jako interpretator wbudowany w przeglądarkę WWW (np. Netscape),
lub jako oddzielny program, który interpretuje pliki “nazwa.class”. Może to być także
implementacja polegająca na przekształceniu – tuż przed rozpoczęciem fazy wykonania – pliku z
B-kodem na program wykonalny, specyficzny dla danej maszyny. Mechanizm ten można określić
jako tworzenie kodu wykonalnego w locie (ang. Just-In-Time, np. kompilator JIT firmy Symantec).
Interpretatory B-kodu, tj. różne maszyny wirtualne, są także często napisane w języku Java.
4. Biblioteka Javy. Środowisko języka Java zawiera bogatą bibliotekę, a w niej zbiór składników dla
prostego, niezależnego od platformy graficznego interfejsu użytkownika.
Rysunek 4-1 ilustruje usytuowanie środowiska programowego języka Java, posadowionego na
dowolnej platformie sprzętowo- programowej komputera (platforma sprzętowo-programowa oznacza
sprzęt komputera i jego system operacyjny).
a)
b)
Program w języku Java
MyProgram.java
Java API
Maszyna wirtualna (JVM)
Klasa System
Platforma sprzętowo-programowa
Środowisko wykonawcze
Rys. 1-1. Usytuowanie systemu Java
Pokazany w części a) rysunku blok Java API (Application Programming Interface) reprezentuje klasy,
interfejsy i obiekty wchodzące w skład aktualnej maszyny wirtualnej, którą zwykle określa się jako
platformę języka Java (Java Platform). Umożliwiają one programom języka Java na dostęp do
zasobów komputera. Może to być dostęp (względnie) systemowo niezależny (implementowany przez
klasę System w pakiecie JDK) i na dostęp systemowo zależny (implementowany przez klasę Runtime ,
reprezentującą środowisko wykonawcze w pakiecie JDK), jak pokazano w części b) rysunku 4-1.
1122838.001.png
4
Języki obiektowe
Tak więc programy użytkownika można kompilować na dowolnej platformie sprzętowo-programowej,
na której posadowiono kompilator języka Java. Otrzymany w wyniku kompilacji B-kod można
traktować jako zbiór instrukcji kodu dla dowolnej implementacji maszyny wirtualnej, jak pokazano na
rysunku 4-2.
Edytor
MyProgram.java
Kompilator
MyProgram.class
Interpretator
Interpretator
PC - Windows 95/NT
SUN - Solaris
Rys. 1-2. Przetwarzanie programów użytkownika
1.1. Elementarny program: tekst źródłowy, kompilacja, interpretacja
Java wprowadza swoistą terminologię dla swoich konstrukcji syntaktycznych i jednostek (modułów)
kompilacji. Programem w języku Java jest aplikacja (application) lub aplet (applet). Aplikacja jest
programem samodzielnym, zaś aplet jest programem wbudowanym (np. w przeglądarkę WWW).
Każda aplikacja musi zawierać dokładnie jeden moduł źródłowy nazywany modułem głównym
aplikacji, którego klasa zawiera publiczną funkcję klasy (funkcje takie są poprzedzane słowem
kluczowym static) main . Tekst źródłowy najprostszego programu może mieć postać:
//plik Hello.java
public class Hello {
public static void main(String args[])
{
System.out.print( " Hello, World!\n " );
} //end main
} // end Hello
Dla skompilowania powyższego programu jego tekst źródłowy należy umieścić w pliku o nazwie
Hello.java. Zakładając, że dysponujemy systemem JDK z kompilatorem javac, program skompilujemy
poleceniem:
javac Hello.java
Udana kompilacja wygeneruje plik z B-kodem o nazwie Hello.class, zawierający sekwencję instrukcji
dla interpretatora JVM. Kod ten wykonujemy przez wywołanie interpretatora o nazwie java
poleceniem:
java Hello
Interpretator wyszuka plik o nazwie Hello.class, ustali, czy klasa Hello zawiera publiczną metodę
statyczną main i wykona instrukcje zawarte w bloku main. Zauważmy przy okazji, że w języku Java
wszystkie stałe, zmienne i funkcje są elementami składowymi klas; nie ma wielkości globalnych,
definiowanych poza klasą. Ponadto nie deklaruje się metod (funkcji) składowych jako rozwijalnych
(inline) bądź nie – decyzja należy do kompilatora.
W przykładowym programie do metody main jako parametr jest przekazywana (z wiersza
rozkazowego) tablica obiektów (łańcuchów) klasy String; metoda main nie zwraca wyniku (typem
zwracanym jest void ), zaś wartością parametru arg[0] jest pierwszy po nazwie programu spójny ciąg
znaków. Ciało main zawiera jedną instrukcję
System.out.print( " Hello, World!\n " );
(W języku Java każda instrukcja kończy się średnikiem, który pełni rolę symbolu terminalnego).
Słowo System jest nazwą klasy w standardowym środowisku języka. Klasa System zawiera
statyczny obiekt składowy typu PrintStream o nazwie out ; wywołanie System.out oznacza
1122838.002.png
Java
5
pisanie do standardowego strumienia wyjściowego. Klasa PrintStream zawiera szereg przeciążeń
metody o nazwie print ; jedno z nich przyjmuje parametr typu String . Kompilator automatycznie
tłumaczy literał stały "Hello, World\n" na odpowiedni obiekt klasy String ; odnośnik (referencja) do
tego obiektu jest przekazywana do metody System.out.print() . Metoda print() generuje
jeden wiersz wyjściowy i powraca do metody main , która kończy wykonanie.
1.2. Klasy: definicja, dziedziczenie, tworzenie obiektów
Klasę Javy można traktować jako wzorzec i jednocześnie generator obiektów. Jako wzorzec klasa
zapewnia hermetyzację (zamknięcie w jednej jednostce syntaktycznej) danych i metod oraz ukrywanie
informacji, które nie powinny być widoczne dla użytkownika. Jako generator zapewnia tworzenie
obiektów za pomocą operatora new, którego argumentem jest konstruktor klasy.
Definicja klasy ma postać:
Deklaracja klasy
{
Ciało klasy
}
Deklaracja klasy składa się w najprostszym przypadku ze słowa kluczowego class i nazwy klasy.
Przed słowem kluczowym class może wystąpić jeden ze specyfikatorów: abstract , public , final , lub
dwa z nich, np. public abstract, public final. Specyfikator abstract odnosi się do klas abstrakcyjnych,
które nie mogą mieć wystąpień, zaś final deklaruje, że dana klasa nie może mieć podklas. Brak
specyfikatora oznacza, że dana klasa jest dostępna tylko dla klas zdefiniowanych w tym samym
pakiecie. Specyfikator public mówi, że klasa jest dostępna publicznie. Klasa abstrakcyjna może
zawierać metody abstrakcyjne (bez implementacji, poprzedzone słowem kluczowym abstract ; w
miejscu ciała metody abstrakcyjnej występuje średnik).
Po nazwie klasy mogą wystąpić frazy: ‘extends nazwa_superklasy’ oraz ‘implements
nazwy_interfejsów’. Fraza ‘extends nazwa_superklasy’ mówi, że klasa dziedziczy (zawsze publicznie)
od klasy nazwa_superklasy, zaś ‘implements nazwy_interfejsów’ deklaruje, że w danej klasie zostaną
zdefiniowane metody, zadeklarowane w implementowanych interfejsach. Jeżeli dana klasa
implementuje więcej niż jeden interfejs, wtedy nazwy kolejnych interfejsów oddziela się przecinkami.
Podklasa klasy abstrakcyjnej zawierającej metody abstrakcyjne może podawać definicje metod
abstrakcyjnych. Podklasa podająca te definicje staje się klasą konkretną, tj. może mieć wystąpienia.
Każda klasa, która odziedziczy metodę abstrakcyjną, ale nie dostarczy jej implementacji, sama staje
się klasą abstrakcyjną, a jej definicja także musi być poprzedzona słowem kluczowym abstract .
) Uwaga. W języku Java każda klasa dziedziczy od predefiniowanej klasy Object. Zatem, jeżeli w
definicji klasy nie występuje fraza extends, to jest to równoważne niejawnemu wystąpieniu w tej
definicji frazy ‘extends Object’.
Zauważmy, że oprócz słowa kluczowego class i nazwy klasy wszystkie pozostałe elementy w
deklaracji klasy są opcjonalne. Jeżeli nie umieścimy ich w deklaracji, to kompilator przyjmie
domyśnie, że klasa jest niepubliczną, nieabstrakcyjną i niefinalną podklasą predefiniowanej klasy
Object.
Ciało klasy jest zamknięte w nawiasy klamrowe i może zawierać zmienne składowe (to jest pola lub
zmienne wystąpienia), zmienne klasy (statyczne, tj. poprzedzone słowem kluczowym static ),
konstruktory i metody oraz funkcje klasy (statyczne). Nazwa każdej zmiennej składowej, zmiennej
klasy, metody lub funkcji klasy musi być poprzedzona nazwą typu (np. boolean, double, char, float,
int, long, void). Przed nazwą typu może wystąpić jeden ze specyfikatorów dostępu: private (dostęp
tylko dla elementów klasy, np. private double d;), protected (dostęp tylko w podklasie, nawet jeśli
podklasa należy do innego pakietu; nie dotyczy zmiennych klasy) lub public (dostęp publiczny). Brak
specyfikatora oznacza, że dany element jest dostępny tylko dla klas w tym samym pakiecie. Po
specyfikatorze dostępu może wystąpić słowo kluczowe final . Słowo final przed nazwą typu zmiennej
wystąpienia lub zmiennej klasy deklaruje jej niemodyfikowalność (np. public static final int i = 10;),
zaś w odniesieniu do metody oznacza, że nie może ona być redefiniowana w podklasie (np. public
final void f(int i) {/* ... */ }).
6
Języki obiektowe
Dostęp do elementów klasy uzyskuje się za pomocą operatora kropkowego. Jeżeli element danej klasy
(zmienna lub metoda) przesłania (overrides) jakiś element swojej superklasy, to można się do niego
odwołać za pomocą słowa kluczowego super, jak w poniższym przykładzie:
class ASillyClass /* Deklaracja klasy */
{
static final int MAX = 100; /** Definicja stałej */
boolean aVariable;/* Deklaracja zmiennej wystąpienia */
static public int x = 10; // Definicja zmiennej klasy
void aMethod() { // Definicja metody
aVariable = true;// Instrukcja przypisania
} // end aMethod
} // end aSillyClass
class ASillerClass extends ASillyClass {
boolean aVariable;
void aMethod() {
aVariable = false;
super.aMethod(); /* Wywołanie metody superklasy */
System.out.println(aVariable);
System.out.println(super.aVariable);
} // end aMethod
} // end ASillerClass
Klasy i omawiane niżej interfejsy są typami referencyjnymi (odnośnikowymi). Wartościami
zmiennych tych typów są odnośniki do wartości lub zbiorów wartości reprezentowanych przez te
zmienne. Np. instrukcja
ASillyClass oob;
jedynie powiadamia kompilator, że będziemy używać zmiennej oob , której typem jest ASillyClass.
Do zmiennej oob możemy przypisać dowolny obiekt typu ASillyClass utworzony za pomocą
operatora new:
oob = new ASillyClass();
W powyższej instrukcji argumentem operatora new jest generowany przez kompilator konstruktor
ASillyClass() klasy ASillyClass, który inicjuje obiekt utworzony przez operator new. Operator new
zwraca odnośnik do tego obiektu, po czym przypisuje go do zmiennej oob .
Jeżeli dana klasa nie zawiera deklaracji konstruktorów, to kompilator dostarcza konstruktor domyślny
z pustym wykazem argumentów, który w swoim bloku wywołuje konstruktor super() jej bezpośredniej
nadklasy. Weźmy dla ilustracji definicję klasy Point:
public class Point { int x, ,y; }
Jest ona równoważna definicji
public class Point { int x, ,y; public Point() { super(); } }
z niejawnym wywołaniem dostarczanego przez kompilator konstruktora superklasy, od której
bezpośrednio dziedziczy klasa Point.
Podobne, niejawne wywołania konstruktora super() są wykonywane w drzewach dziedziczenia.
Rozpatrzmy następujący program:
//plik Super1.java
class Point { int x,y; Point() { x=1;y=2; } }
class CPoint extends Point { public int color = 0xFF00FF; }
public class Super1 {
public static void main(String args[]) {
CPoint cp = new CPoint();
System.out.println("cp.color= " + cp.color);
System.out.println("cp.x= " + cp.x);
}//end main
}//end Super1
Instrukcja CPoint cp = new CPoint(); tworzy nowe wystąpienie klasy CPoint . Najpierw
jest przydzielany obszar w pamięci dla obiektu cp , aby mógł przechowywać wartości x oraz y , po
Zgłoś jeśli naruszono regulamin