2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 1
2. Klasa, obiekt, interfejs, pakiet
1. Definicja klasy
2. Cykl
ż
ycia obiektu
3. Kapsułkowanie dost
ę
pu do składowych
4. Dziedziczenie klas
5. Klasy zagnie
ż
d
ż
one
6. Interfejs
7. Pakiet
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 2
Cechy programowania obiektowego (przypomnienie)
•
Klasa - implementacja abstrakcyjnego typu danych - prototyp obiektów
pewnego typu - wyznacza strukturę danych i operacji dla tych obiektów.
•
Obiekt - instancja klasy - związek zmiennych (pól) i funkcji
składowych (metod).
•
Komunikowanie się obiektów - obiekt wykonuje wymaganą metodę na
przekazanych mu argumentach.
•
Dziedziczenie - klasa pochodna dziedziczy strukturę danych i
zachowanie ze swojej klasy bazowej ("nadklasy").
•
Metody polimorficzne – różne wersje metody w klasach pochodnych,
dynamiczne wiązanie wersji metody.
•
Kapsłkowanie – poziomy dostępu do składowych klasy.
•
Interfejs - jest to kontrakt (model zachowania obiektu) w postaci zbioru
metod i deklaracji stałych - jeśli dana klasa implementuje interfejs to
"zobowiązuje się" do implementacji wszystkich metod deklarowanych
w tym interfejsie.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 3
2.1 Definicja klasy
Przykład 2.1
. Klasa implementująca stos (kolejkę LIFO).
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 4
W definicji klasy Stack wykorzystano obiekt klasy Vector - tablicy obiektów
o zmiennej liczbie elementow.
Definicja klasy składa si
ę
z:
deklaracji klasy (podaje nazwę klasy, specyfikację dostępu i ew.
dziedziczenie)
treści (definicji) klasy.
Deklaracja klasy
Obligatoryjne
są: słowo kluczowe
class
i
nazwaKlasy.
Dla
opcjonalnych
części możliwe są domyślne specyfikacje:
klasa niepubliczna,
klasa konkretna (nieabstrakcyjna),
klasa nie-finalna (może istnieć jej klasa pochodna)
będąca klasą pochodną klasy Object,
klasą nie implementującą interfejsów.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 5
public - klasa jest dostępna dla wszystkich klas; w przeciwnym razie tylko
dla klas z tego samego pakietu.
abstract - nie mogą istnieć instancje tej klasy.
final - nie można dziedziczyć tej klasy.
extends Super - określa, że klasa Super jest klasą bazową.
implements Interfaces - okresla, że klasa implementuje jeden lub więcej
interfejsów (podawanych po przecinku).
Tre
ść
klasy
Ujęta w parę nawiasów { , } , zawiera:
deklaracje wszystkich zmiennych składowych (pól) (w tym pól "obiektów" i
pól statycznych - "klasowych");
deklaracje i definicje wszystkich funkcji składowych (metod) (w tym metod
wywoływanych na rzecz obiektu lub metod statycznych - "klasowych");
ewentualnie definicje 1-go lub więcej konstruktorów.
Np.
klasa Stack w przykładzie 2.1 zawiera pole items klasy Vector , jeden
konstruktor bezargumentowy i 3 metody - push, pop, isEmpty.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 6
Konstruktory
Przykład 2.2
. Utwórzmy dwa konstruktory w klasie
Stack
.
public Stack() {
// 1-szy konstruktor
items = new Vector(10);
}
public Stack(int initialSize) {
// 2-gi konstruktor
items = new Vector(initialSize);
}
Wywołania obu konstruktorów:
new Stack(10);
// 2-giego
new Stack();
// 1-szego
Domyślny konstruktor (o pustym kodzie inicjalizaci) jest dostępny
automatycznie wtedy, gdy w klasie nie zdefiniowano
ż
adnego
konstruktora.
Konstruktor w klasie dziedziczonej
Przykład 2.3.
Wywołanie konstruktora klasy bazowej w klasie pochodnej.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 7
class AnimationThread extends Thread {
// Dziedziczenie po Thread
int framesPerSecond;
int numImages;
Image[] images;
AnimationThread(int fps, int num) {
// Definicja konstruktora
super("AnimThread");
// Wywołanie konstruktora klasy bazowej -
// jeśli występuje, to powinno być pierwszą instrukcją w
// konstruktorze klasy pochodnej.
this.framesPerSecond = fps;
this.numImages = num;
this.images = new Image[numImages];
for (int i = 0; i <= numImages; i++) {
. . .
// Załaduj obrazy.
. . .
}
}
. . .
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 8
Kwalifikatory dost
ę
pu
, które mogą być podane w deklaracji konstruktora:
private - żadna inna klasa nie może tworzyć (bezpośrednio) obiektów tej
klasy;
protected - klasy pochodne danej klasy i klasy należące do tego samego
pakietu mogą tworzyć obiekty tej klasy.
public - każda klasa może tworzyć obiekty naszej klasy.
brak specyfikatora dostępu - każda klasa z tego
samego pakietu
może tworzyć
obiekty tej klasy.
Deklaracje pól klasy
deklaracjaKlasy {
deklaracje pól
deklaracje i definicje metod
}
Np. w klasie Stack .
private Vector items;
Specyfikuje prywatny dostęp do składowej.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 9
W deklaracji pola mogą wystąpic też
inne specyfikatory:
Poziomy dostępu:
public, protected, package, private
static - deklaracja pola
statycznego
(lub metody statycznej).
final - deklaracja
stałego
pola.
transient - zaznacza te składowe, które nie powinny być serializowane.
volatile - zaznacza pole jako ulotne, mające nie podlegać optymalizacji.
Uwaga:
pole i metoda jednej klasy mogą mieć
tę samą
nazwę.
Przykład 2.4.
public class Stack {
private Vector items;
// Nazwa pola items
public Vector items() {
// Nazwa metody items
. . .
}
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 10
Definiowanie metod w klasie
Przykład 2.5.
Metoda push w klasie Stack:
Deklaracja metody
- specyfikacja poziomu dostępu, typ wyniku, nazwa,
lista parametrów (argumentów formalnych).
Obligatoryjne
części deklaracji to:
typWyniku nazwaMetody ()
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 11
Wszystkie elementy deklaracji metody:
accessLevel - poziom dostępu - public, protected, package, private.
static - deklaruje metodę jako statyczną ("klasową").
abstract - nie posiada defincji, jej klasa musi być abstrakcyjna.
final - nie może być przysłonieta przez metody klas pochodnych.
native - metoda rodzima, napisana w innym języku programowania.
synchronized - synchronicznie wywoływana metoda względem wielu
wątków.
returnType - typ zwracanego wyniku.
methodName - nazwa metody - dowolny legalny identyfikator.
( paramlist ) - lista parametrów.
[throws exceptions] - lista wyjątków zgłaszanych przez metodę.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 12
Tre
ść
definicji metody
Wynik zwracany przez metodę
- jeśli zadeklarowano wynik zwracany przez
metodę (różny od void) to musi w jej definicji wystąpić instrukcja return
zwracająca zmienną lub obiekt zgodnego typu.
Można zwrócić:
•
zmienną typu prostego -
przez wartość
-
•
lub obiekt klasy -
przez referencję
.
Przykład 2.6
public synchronized Object pop() {
int len = items.size();
Object obj = null;
if (len == 0)
throw new EmptyStackException();
obj = items.elementAt(len - 1);
items.removeElementAt(len - 1);
return obj;
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 13
Metoda może zwrócić obiekt typu klasy pochodnej
względem klasy
zadeklarowanego wyniku.
Przykład 2.7
. Niech istnieje hierarchia klas:
Object <-- Number <-- ImaginaryNumber
Niech deklarowany typ wyniku metody to
Number
:
public Number returnANumber() {
. . .
}
Metoda może też zwrócić obiekt klasy
ImaginaryNumber
lecz nie klasy
Object
.
Przeciążona nazwa metody
- metody przeciążone różnią się
liczbą
lub
typem parametrów
.
Przesłanianie metod
- metoda w klasie pochodnej może przesłonić metodę jej klasy bazowej - obie
muszą mieć
ten sam typ wyniku, nazwę i listę parametrów
.
Parametry metody:
typy proste, tablice, typy obiektowe.
Nie można przekazywać
metod jako parametrów
.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 14
Nazwy parametrów metody muszą być unikalne w ramach jednej metody a
także nazw parametrów frazy
catch
zdefiniowanej w danej metodzie.
Przekazywanie przez wartość
Zmienne proste są kopiowane a zmienne referencyjne też (ale nie obiekty przez
nie referowane).
Zmienna prosta ani też zmienna referencyjna nie mogą być modyfikowane, ale
obiekt referowany - może.
W treści definicji metody możliwe są odwołania:
-
this
- odwołanie do danego obiektu;
-
super
- odwołanie do składowych pod-obiektu klasy bazowej.
Lokalne zmienne metody - zmienne deklarowane w treści metody są lokalne -
widoczne tylko w zasięgu wewnętrznym tej metody.
Np.
Object findObjectInArray(Object o, Object[] arrayOfObjects) {
int i;
// lokalna zmienna
...
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 15
2.2 Cykl
ż
ycia obiektu
Instrukcja definicji obiektu
posiada 3 części:
1.
Definicja zmiennej typu
referencji do obiektu klasy.
2.
Utworzenie obiektu: operator new alokuje pamięć dla obiektu.
3.
Inicjalizacja: wywołanie konstruktora klasy.
Definicja zmiennej:
typ nazwa
Dla typu klasy lub interfejsu zmienna przechowuje adres do obiektu klasy, ale
nie jest on dostępny bezpośrednio lecz stanowi referencję. Do momentu
przypisania jej adresu obiektu przechowuje ona zerową referencję.
Utworzenie obiektu:
new typ(argumenty)
Operator new zwraca referencję do nowo utworzonego obiektu.
Inicjalizacja obiektu: w konstruktorze klasy.
Przykład 2.8
public class Point {
public int x = 0;
public int y = 0;
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 16
public Point(int x, int y) {
// Konstruktor
this.x = x;
this.y = y;
}
}
Dla zupełności - definicja klasy Rectangle korzystającej z klasy Point:
public class Rectangle {
public int width = 0;
public int height = 0;
public Point origin;
// ...
public Rectangle(int w, int h) {
this(new Point(0, 0), w, h);
}
public Rectangle(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 17
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
public int area() {
return width * height;
}
}
Przykład 2.9.
Zmienna referencyjna a obiekt klasy:
Point origin_one = new Point(23, 94);
Rectangle rect_one = new Rectangle(origin_one, 100, 200);
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 18
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 19
Co możemy robić z obiektem?
Odczytać jego stan - pobrać wartości jego pól.
Zmienić stan obiektu - zmienić wartości pól obiektu.
Wykonać akcję - wywołać metodę dla obiektu.
Dostęp do pola obiektu:
Nazwa kwalifikowana:
referencjaObiektu.nazwa Pola
Zwykle posługujemy się nazwaną referencją, ale może też być nienazwana
referencja, np.:
int height = new Rectangle().height;
// Możliwe ale nieefektywne
Ukrywanie dostępu do pól
Np. w klasie Rectangle zdefiniujemy metody setWidth, setHeight, getWidth,
getHeight dla zapisu i odczytu wartości pól obiektu, co umożliwia:
sprawdzanie poprawności przekazywanych danych,
uniezależnia użytkownika od typu i nazwy pola.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 20
Wywołania metody
referencjaDoObiektu.nazwaMetody(listaArgumentów);
referencjaDoObiektu.nazwaMetody();
Np.
System.out.println("Powierzchnia rect_one: " + rect_one.area());
rect_two.move(40, 72);
Usuwanie obiektu - "Garbage Collector"
Ś
rodowisko wykonania Javy (JRE) usuwa samoczynnie obiekt, gdy wykrywa,
ż
e nie jest już dłużej używany w programie - garbage collection - brak
referencji do tego obiektu w programie.
"Garbage collector" jest wykonywany automatycznie co pewien czas. Można go
też wywołać jawnie:
System.gc()
Metoda "finalize" (znana od klasy Object - nadklasie wszystkich klas)
Przed usunięciem obiektu przez GC wywoływana jest metoda finalize, dając
programiście szansę do zdefiniowania czynności "czyszczących" związanych z
usunięciem obiektu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 21
2.3 Poziomy dost
ę
pu do składowych klasy
Cztery poziomy dostępu:
private, protected, public
i (jeśli niezdefiniowane)
package.
Uwaga: Java 1 posiadała jeszcze jeden specyfikator dostępu -
private protected
.
Nie występuje on w Java 2.
Specyfikator
klasa
klasa
pochodna
ten pakiet
pozostałe
klasy
private
X
protected
X
X*
X
public
X
X
X
X
package
X
X
Uwaga:
(*)
składowe
protected
są dostępne dla klasy pochodnej,
zdefiniowanej w innym pakiecie niż klasa bazowa, tylko wtedy, gdy odwołania
następują dla obiektu tej klasy a nie klasy bazowej.
Private.
Np. niech pewna klasa Alpha zawiera prywatne składowe:
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 22
class Alpha { private int iamprivate;
private void privateMethod()
{ System.out.println("privateMethod"); }
}
Tylko obiekty klasy Alpha mogą odwoływać się do pola iamprivate i
wywoływać metodę privateMethod. Beta - inna klasa w tym samym pakiecie:
class Beta { void accessMethod() {
Alpha a = new Alpha();
a.iamprivate = 10;
// niedozwolone
a.privateMethod();
// niedozwolone
}
}
Obiekty pewnej klasy mogą oczywiście odwoływać się do prywatnych
składowych innego obiektu tej samej klasy. Np.
class Alpha { private int iamprivate;
boolean isEqualTo (Alpha anotherAlpha) {
if (this.iamprivate
==
anotherAlpha.iamprivate) return true;
else return false; }
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 23
Protected
- dostęp mają: klasa, jej klasa pochodna i wszystkie klasy należące
do tego samego pakietu co omawiana klasa. Np.
package Greek;
public class Alpha { protected int iamprotected;
protected void protectedMethod() {
System.out.println("protectedMethod"); }
}
Niech klasa Delta będzie klasą pochodną od Alpha ale zdefiniowaną w innym
pakiecie Latin.
package Latin;
import Greek.*;
class Delta extends Alpha {
void accessMethod(Alpha a, Delta d) {
a.iamprotected = 10;
// niedozowolone
d.iamprotected = 10;
// dozwolone
a.protectedMethod();
// niedozwolone
d.protectedMethod();
// dozwolone
}
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 24
Składowe statyczne klasy
Np.
class MojaKlasa {
float zmFloat;
// Pole powielane w obiektach klasy
static float zmKlasowa;
// Pole statyczne - unikalne dla obiektów klasy
}
Dostęp do składowej statycznej - przez nazwę klasy lub dowolny jej obiekt.
Po napotkaniu definicji klasy tworzona jest
jedyna kopia pola statycznego
.
Metoda statyczna nie uzyskuje referencji this.
Metoda statyczna
może odwoływać się jedynie
do pól statycznych
tej klasy.
Składowe statyczne są dostępne poprzez nazwę klasy, nie ma nawet potrzeby
definiowania obiektów klasy. Np.:
KlasaX.ustawX(1);
System.out.println("KlasaX.x = " + KlasaX.x());
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 25
Inicjalizacja pól
Składowe zwykłe i statyczne
mogą być inicjalizowane
w miejscu deklaracji.
Np.:
class KlasaBaB {
static final int MAX_POKOJE = 10;
boolean zajety = false;
}
Ograniczenia:
-
Inicjalizacja musi dac się wyrazić wyrażeniem przypisania.
-
Nie można wywołać w tym celu metody mogącej zgłosić obsługiwany
wyjątek.
-
Jeśli podczas inicjalizacji wołana jest metoda, która zgłosi wyjątek, to nie
jest możliwy powrót do programu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 26
Inicjalizacja składowej statycznej
w innym miejscu niż miejsce deklaracji
składowej wymaga bloku statycznej inicjalizacji.
static {
// Kod inicjalizacji
}
Przykład 2.10
. Blok statycznej inicjalizacji.
import java.util.ResourceBundle;
class Errors {
static ResourceBundle errorStrings;
// Deklaracja bez inicjalizacji
static {
try { errorStrings = ResourceBundle.getBundle("ErrorStrings");
}
catch (java.util.MissingResourceException e) {
// obsługa wyjątku i wznowienie wykonania programu
}
}
}
Podczas inicjalizacji (w bloku try) może powstać błąd (nie ma wiązki), ale
będzie możliwe jego obsłużenie i kontynuacja wykonywania programu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 27
Liczba bloków statycznej inicjalizacji w programie jest dowolna.
Inicjalizacja zwykłej składowej
powinna odbyć się w konstruktorze klasy.
Przykład 2.11
. Inicjalizacja składowych obiektu w konstruktorze:
import java.util.ResourceBundle;
class Errors {
ResourceBundle errorStrings;
// Deklaracja. Inicjalizacja w konstruktorze
Errors() {
try { errorStrings = ResourceBundle.getBundle("ErrorStrings");
}
catch (java.util.MissingResourceException e) {
// obsługa wyjątku i wznowienie wykonania programu
}
}
}
Bloki inicjalizacji instancji
Klasy anonimowe nie posiadają konstruktorów - w celu inicjalizacji
składowych obiektowych istnieje mechanizm bloku inicjalizacji instancji.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 28
2.4 Dziedziczenie klas
extends identyfikuje dziedziczenie - dziedziczenie pojedyncze - tylko jedna
klasa bazowa w dziedziczeniu.
Przy braku dziedziczenia nasza klasa dziedziczy domyślnie z klasy Object
zdefiniowanej w java.lang.
Klasa pochodna dziedziczy:
-
wszystkie składowe, które są dostępne dla niej (public lub protected lub
package - jeśli klasa należy do tego samego pakietu co jej klasa bazowa) i
-
których nie przesłania (pola) lub nie nadpisuje (metody);
Konstruktorów nie dziedziczy się.
Nadpisana metoda może mieć
inną listę wyjątków
niż metoda dziedziczona, ale
nie zawiera nazw nie występujących na liście wyjątków metody dziedziczonej.
Specyfikator dostępu do metody nadpisanej
może zezwolić na większy dostęp
niż metoda dziedziczona ale nie na mniejszy. Np. metoda chroniona (protected)
w klasie bazowej może zostać publiczna ale nie prywatna.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 29
Wywołanie metody dziedziczonej
super.nazwaMetody();
Metody klasy bazowej,
których nie można
nadpisać w klasie pochodnej:
-
metoda zadeklarowana jako final w klasie bazowej;
-
metoda statyczna (można jedynie ukryć metodę statyczną dziedziczoną
przez jej ponowne zadeklarowanie).
Metody klasy bazowej
które muszą
zostać nadpisane w klasie pochodnej:
-
metody zadeklarowane jako abstrakcyjne w klasie bazowej,
-
lub gdy klasa bazowa jest abstrakcyjna.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 30
Dziedziczenie po klasie
Object
–
głównej klasie hierarchii klas
Metody klasy Object, które mogą być nadpisane w naszej klasie:
-
clone
-
equals/hashCode
-
finalize
-
toString
Nie mogą być nadpisane metody podane jako "
final
" :
-
getClass
-
notify
-
notifyAll
-
wait
Metoda
clone
- tworzenie nowego obiektu na podstawie już istniejącego:
obiektKlonowany.clone();
Klasa obiektu musi implementować interfejs
Cloneable
- w przeciwnym razie
powstanie wyjątek typu
CloneNotSupportedException
.
Przykład 2.12.
Implementacja metody clone0 w klasie Stack:
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 31
public class Stack implements Cloneable
{ private Vector items;
// ...
protected Object clone() {
try { Stack s = (Stack)super.clone();
// Klonuj obiekt klasy Stack
s.items = (Vector)items.clone();
// Klonuj obiekt klasy Vector
return s;
// Wynik
} catch (CloneNotSupportedException e) {
// Nie powinno się zdarzyć , gdyż
Stack
jest „
Cloneable”
throw new InternalError();
}
}
}
Uwaga:
metoda clone() nigdy nie powinna wołać operatora new ani konstruktora -
zamiast tego wołać powinno się super.clone() i utworzyć obiekt właściwego
typu a następnie metody clone() dla składowych obiektu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 32
•
Metody
equals
i
hashCode
- muszą być jednocześnie nadpisane.
Metoda equals sprawdza, czy dwa obiekty są identyczne, tzn. czy przechowują
tę samą wartość. Np.
Integer one = new Integer(1), anotherOne = new Integer(1);
if (one.equals(anotherOne)) System.out.println("Obiekty są równe");
Metoda hashCode zwraca wartość typu int, będącą indeksem dla obiektu w
wykazie asocjacyjnym (hash table) - zwykle nie jest to odwzorowanie unikalne
dla obiektów danej klasy.
Metoda
finalize
- wywoływana jest automatycznie przed usunięciem obiektu.
Metoda
toString
- zamienia obiekt klasy Object w obiekt klasy String
umożliwiając "tekstowy wydruk" obiektu za pomocą System.out.println.
Np. reprezentacja napisu dla liczby typu Integer to tekstowa postać liczby; napis
dla obiektu klasy Thread podaje atrybuty obiektu takie, jak nazwa i priorytet.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 33
Metoda
getClass
Metoda zwraca reprezentację "run-time" klasy obiektu w postaci obiektu typu
Class. Można dowiedzieć się z niego o nazwie klasy, jej klasie bazowej i
interfejsach, które implementuje klasa. Np.
void PrintClassName(Object obj)
{ System.out.println("Klasa obiektu to " + obj.getClass().getName()); }
Można utworzyć nowy obiekt tej samej klasy co pierwszy obiekt, np.:
Object createNewInstanceOf(Object obj)
{ return obj.getClass().newInstance(); }
String.class
lub
Class.forName("String")
- zwraca obiekt klasy
Class
opisujący typ "
String
".
Metody
notify, notifyAll, wait
- ich zadaniem jest synchronizacja wątków.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 34
2.5 Klasy zagnie
ż
d
ż
one i wewn
ę
trzne
Definicja klasy jako składowej innej klasy. Np.
class KlazaZewnetrzna{ // ...
class KlasaWewnetrzna { /*... */ }
static class KlasaZagniezdzona { /* ... */}
}
-
Klasa zagnieżdżona ma dostęp do składowych klasy obejmującej, również
składowych prywatnych.
-
Klasa zagnieżdżona może zostać zadeklarowana jako statyczna - wtedy jest
związana z obejmującą ją klasą
.
-
Klasa niestatyczna zagnieżdżona
jest klasą wewnętrzną w obiekcie klasy
obejmującej. Obiekt klasy wewnętrznej
może wystąpić jedynie w instancji
klasy obejmującej.
-
Klasa zagnieżdżona może być deklarowana jako abstract lub final.
-
Również specyfikatory dostępu jak dla składowych klasy mają tu
zastosowanie: private, public, protected, i package.
Klasy mogą być też definiowane w treści metod lub w dowolnym bloku kodu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 35
Wewn
ę
trzne klasy
Przykład 2.13.
Niech istnieje interfejs "Enumeration" o metodach:
public boolean posiadaElementy();
public Object nastepnyElement();
Klasa implementująca interfejs może stworzyć pętlę nad elementami obiektu
while (posiadaElementy())
nastepnyElement();
Gdyby klasa "Stack" implementowała "Enumeration" powyższa pętla dla
obiektu mogłaby wykonać się najwyżej raz i nie byłoby możliwe jednoczesne
wykonanie dwóch pętli.
Stąd pomysł aby klasa wewnętrzna "StackEnum" - wspomagająca (tzw.
"adapter") - realizowała ten interfejs.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 36
public class Stack {
private Vector elementy;
...// kod metod i konstruktora pomijamy...
public Enumeration enumerator() {
return new StackEnum();
}
class StackEnum implements Enumeration {
int aktualnyElem = elementy.size() - 1;
public boolean posiadaElementy() {
return (aktualnyElem
!=
0);
}
public Object nastepnyElement() {
if (! posiadaElementy()) throw new NoElementException();
else return elementy.elementAt (aktualnyElem --); }
}
}
// Komentarz: klasa "StackEnum" odnosi się bezpośrednio do składowej
// elementy w klasie Stack.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 37
Klasa wewn
ę
trzna anonimowa
Przykład 2.14.
Teraz rolę klasy "adaptera", implementującej interfejs, przejmie
klasa anonimowa w klasie Stack.
public class Stack { private Vector elementy;
...// kod metod i konstruktora pomijamy...
public Enumeration enumerator() {
return new Enumeration() {
// Klasa anonimowa
int currentItem = elementy.size() - 1;
public boolean posiadaElementy() {
return (aktualnyElem != 0); }
public Object nastepnyElement() {
if (! posiadaElementy()) throw new NoElementException();
else return elementy.elementAt ( aktualnyElem --); }
}
}
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 38
Kwalifikatory dost
ę
pu dla klas zagnie
ż
d
ż
onych (wewn
ę
trznych):
a. Jedynymi u
ż
ytkownikami tej klasy wewm
ę
trznej s
ą
instancje klasy obejmuj
ą
cej lub jej klas pochodnych.
protected
b. Ka
ż
dy mo
ż
e u
ż
ytkowa
ć
tak
ą
klas
ę
.
public static
c. Tylko instancje klasy deklaruj
ą
cej mog
ą
u
ż
ytkowa
ć
t
ę
klas
ę
zagnie
ż
d
ż
on
ą
(wewn
ę
trzn
ą
) a ka
ż
da
instancja mo
ż
e u
ż
ytkowa
ć
j
ą
wiele razy.
private
d. Ta klasa zagnie
ż
d
ż
ona (wewn
ę
trzna) jest u
ż
yta
tylko raz dla utworzenia obiektu implementuj
ą
cego
interfejs.
anonimowa (brak
kwalifikatora)
e. Ta klasa zagnie
ż
d
ż
ona posiada informacje o klasie
obejmuj
ą
cej (nie o instancjach) i u
ż
ytkowana jest tylko
przez klas
ę
obejmuj
ą
c
ą
i jej pochodne.
protected static
f. Podobnie jak przypadek e) ale bez klas
pochodnych.
private static
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 39
2.6 Interfejs
-
Interfejs
to zbiór deklaracji metod i ewentualnie pól stałych.
-
Klasa abstrakcyjna
może implementować pewne metody, ale interfejs - nie.
-
Klasa konkretna
posiada co najwyżej jedną klasę bazową ale może
implementować wiele interfejsów.
Definicja interfejsu
DeklaracjaInterfejsu {
TreśćInterfejsu
}
Przykład 2.15
public interface StockWatcher {
// Definicja interfejsu
final String sunTicker = "SUNW";
// Deklaracja stałej symbolicznej
final String oracleTicker = "ORCL";
final String ciscoTicker = "CSCO";
// Deklaracja metody sygnalizującej zmianę wartości akcji
void valueChanged(String tickerSymbol, double newValue);
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 40
Klasa StockMonitor ma służyć do monitorowania cen akcji. Klasa umozliwia
rejestrowanie się innym klasom, które chcą być powiadamiane o zmianach
pewnych akcji.
public class StockMonitor {
public void watchStock( StockWatcher watcher,
String tickerSymbol, double delta) {
// Monitorowana akcja i próg zmiany
...
}
}
Uwagi:
StockWatcher to nazwa interfejsu o jednej metodzie valueChanged.
Obiekt powiadamiany o zmianach akcji musi implementowac ten interfejs i
posiadać metodę valueChanged.
Gdy StockMonitor wykrywa interesującą obserwatora zmianę wywołuje on
metodę valueChanged obserwatora.
Dzięki zastosowaniu interfejsu nie nakładamy na klasy obserwatora żadnych
związków z klasą StockMonitor - moga to być dowolne klasy nie należące do
hierarchii dziedziczenia klasy StockMonitor ani między sobą - muszą jedynie
implementować metodę wybranego interfejsu.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 41
Elementy definicji interfejsu
public - dostępny przez każdą klasę w każdym pakiecie (przy braku public -
dostęp w trybie package);
interface NazwaInterfejsu
(opcjonalnie): extends listaNadinterfejsów - interfejs może posiadac więcej
niż jeden nadinterfejs;
treść interfejsu.
Treść interfejsu
deklaracje metod - wszystkie posiadają specyfikacje (
niejawne
)
public
i
abstract
;
deklaracje stałych symbolicznych (niejawnie są one
public, static
i
final
).
W treści interfejsu
nie mogą
wystąpić specyfikatory składowych:
transient, volatile, synchronized;
private, protected
.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 42
Implementacja interfejsu - jest to kontrakt zachowania się klasy.
Przykład 2.16.
Aplet implementujący interfejs StockWatcher:
public class StockApplet extends Applet implements StockWatcher {
...
public void valueChanged(String tickerSymbol, double newValue) {
if (tickerSymbol.equals(sunTicker)) { ...
// treść pomijamy
} else if (tickerSymbol.equals(oracleTicker)) { ...
// treść pomijamy
} else if (tickerSymbol.equals(ciscoTicker)) { ...
// treść pomijamy
}
}
}
Komentarz: klasa odwołuje się to stałych zdefiniowanych w interfejsie
StockWatcher: sunTicker, oracleTicker, ciscoTicker - poprzez ich proste
nazwy. Nazwa kwalifikowana: StockWatcher.sunTicker
Jeśli klasa implementująca interfejs
nie posiada definicji wszystkich
metod
interfejsu i jego nadinterfejsów to musi być zadeklarowana jako
abstrakcyjna
.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 43
Zastosowanie interfejsu jako typu
- definicja nowego interfejsu oznacza
utworzenie
nowego referencyjnego typu
danych.
Przykład 2.17
public class StockMonitor {
public void watchStock(StockWatcher watcher,
String tickerSymbol, double delta) { ...
// treśc pomijamy
}
}
Do zmiennej referncyjnej typu interfejsu
można
przypisać
tylko
obiekt klasy
implementującej dany interfejs.
Raz ustalone interfejsy nie powinny już ulegać zmianie
Nie powinniśmy uzupełniać definicji interfejsu w późniejszym czasie.
Wymagałoby to zmian w programach implementujących ten interfejs.
Wtedy należy zdefiniować specializowany interfejs, np.:
public interface StockTracker extends StockWatcher {
void currentValue(String tickerSymbol, double newValue);
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 44
2.7 Pakiet
Pakiety stosowane są w celu uniknięcia konfliktu nazw klas i interfejsów,
zapewnienia ochrony dostępu i nadania struktury - pogrupowania powiązanych
ze sobą klas i interfejsów. Np.
java.lang -
zawiera podstawowe klasy języka;
java.io -
wejście - wyjście;
Utworzenie własnego pakietu
Należy podac instrukcję ze słowem kluczowym package na początku pliku. Np.
package graphics;
public class Circle extends Graphic implements Draggable {
. . .
}
----------------------------
package graphics;
public class Rectangle extends Graphic implements Draggable {
. . .
}
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 45
W jednym pliku
można zdefiniować wiele klas, ale
tylko jedna
z nich może
być publiczna
i
jej nazwa
musi odpowiadać
nazwie pliku
.
Plik
pozbawiony
instrukcji package - klasy w nim definiowane wchodzą do
domyślnego nienazwanego pakietu
.
Kwalifikowana nazwa
naszej klasy "Rectangle" to graphics.Rectangle - a
systemowej klasy "Rectangle" - java.awt.Rectangle.
Konwencja dla uniknięcia dublowania się nazw pakietów: producenci
poprzedzają nazwy pakietów internetową nazwą swojej firmy -
nazwaFirmy.nazwapakietu
Z zewnątrz pakietu
istnieje
dostęp
do
publicznych elementów pakietu
. Należy:
-
(1) podać nazwę kwalifikowaną, lub
-
(2) zaimportować pojedynczy element pakietu, lub
-
(3) zaimportować cały pakiet.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 46
Np. (1)
graphics.Rectangle
graphics.Rectangle myRect = new graphics.Rectangle();
(2)
import graphics.Circle;
Circle myCircle = new Circle();
(3)
import graphics.*;
Circle myCircle = new Circle();
Rectangle myRectangle = new Rectangle();
Środowisko wykonania Javy
domyślnie importuje
dwa pakiety
:
-
java.lang
-
domyślny
pakiet.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 47
Konwencja rozmieszczania plików programu
Plik źródłowy umieszczany jest w katalogu o nazwie pakietu do którego klasy
pliku należą.
Np.
nazwa klasy
graphics.Rectangle
katalog pliku
graphics/Rectangle.java
Np.
2. Klasa, obiekt, interfejs, pakiet
W. Kasprzak: Programowanie zdarzeniowe
2 - 48
Plik
*.class
może znaleźć się w innym katalogu niż plik źródłowy:
Np.
Kompilator i interpreter przeszukują katalogi lub pliki ZIP podane jako ścieżka
klas. Np. powyżej byłyby to "
classes
" dla interpretera i "
sources
" dla
kompilatora.
Domyślnie przeszukiwany jest
bieżący katalog
i
plik ZIP
zawierający
klasy
platformy Java danej instalacji
.