Definicje klas i obiektów

Transkrypt

Definicje klas i obiektów
Definicje klas
i obiektów
Tomasz Borzyszkowski
Podstawy
Do tej pory używaliśmy klas jedynie po to, by zdefiniować metodę
main(). Klasy mają znacznie szersze zastosowanie w Java.
W OOP (także w Java) klasy służą do definiowania nowych typów
danych o znacznie większej sile wyrazu niż typy tradycyjne.
Mając definicję klasy możemy tworzyć obiekty typu danej klasy. Klasa
pełni rolę wzorca (schematu budowy) obiektu. Obiekty danej klasy
nazywamy instancjami klasy.
Klasy w Java pozwalają na zastosowanie idei hermetyzacji. Osiąga
się to przez wyspecyfikowanie danych i kodu klasy, operującego na
danych. Proste klasy mogą zawierać tylko dane lub tylko kod lecz
większość klas zawiera zarówno kod jak i dane.
Zwykle użytkownik nie ma bezpośredniego dostępu do danych
obiektu, natomiast ma do dyspozycji metody dostępu do danych,
przewidziane w klasie. Klasa definiuje więc interfejs do danych
swoich instancji (właściwie: zmiennych instancji).
2
Ogólny schemat klasy
W Java definicja klasy rozpoczyna się słowem kluczowym class.
Ogólna postać definicji klasy jest następująca:
class nazwaKlasy {
typ zmiennaInst_1;
// ...
typ zmiennaInst_n;
Zobacz:
 BoxDemo.java
 BoxDemo2.java
typ metoda_1(parametry) {
// ciało metody_1
}
// ...
typ metoda_n(parametry) {
// ciało metody_n
}
} // koniec definicji klasy
3
Deklaracja obiektów
Wytworzenie obiektu z danej klasy to zadanie dwuetapowe:
 Po pierwsze: trzeba zadeklarować zmienną typu danej klasy.
Zmienna taka nie jest obiektem. Jest tylko zmienną mogącą
wskazywać na obiekt.
Kod
Box myBox;
Efekt
null
myBox
 Po drugie: trzeba utworzyć obiekt danej klasy i przypisać go do
zmiennej. Operator new dynamicznie rezerwuje (w czasie
wykonania) obszar pamięci na obiekt i zwraca wskazanie do tego
obszaru.
width
Efekt
Kod
myBox = new Box();
height
myBox
depth
4
Konstruowanie obiektu
Postać ogólna:
zmiennaKlasy = new nazwaKlasy();
nazwaKlasy jest nazwą klasy, której obiekt właśnie powołujemy.
Nazwa ta, waraz z ewentualnymi parametrami wyznacza konstruktor
klasy. Konstruktor to specjalna metoda, o nazwie takiej jak klasa.
Definiuje ona co trzeba zrobić by utworzyć obiekt danej klasy.
Jeżeli klasa nie posiada konstruktora, to jest wywoływany konstruktor
domyślny. Po utworzeniu konstruktora dla klasy konstruktor domyślny
nie jest dostępny.
Konstruktory nie posiadają typu wynikowego, nawet void.
Dzieje się tak dlatego, że niejawnym typem wynikowym każdego
konstruktora jest klasa, której obiekt konstruktor tworzy.
Prócz powołania obiektu, zadaniem konstruktora jest jego
inicjalizacja, tak by po utworzeniu był w pełni sprawnym obiektem.
Zobacz: BoxDemo3.java
5
Słowo kluczowe this
Czasem metoda obiektu potrzebuje odwołać się do obiektu
wywołującego tę metodę.
Umożliwia to słowo kluczowe this. Wewnątrz metody this oznacza
obiekt, na rzecz którego wywołano metodę.
this jest często używany do tworzenia metod polimorficznych,
ale o tym opowiemy później.
W Java nie można deklarować dwóch takich samych zmiennych
lokalnych w obrębie jednego zakresu, jednak istnieje możliwość
przesłonięcia zmiennych instancyjnych klasy przez parametry metody.
Wewnątrz metody zmienne instancyjne byłyby niedostępne, gdyby nie
możliwość użycia zmiennej this:
Box (double width, double height, double depth){
this.width = width;
this.height = height;
this.depth = depth;
}
6
Zbieracz śmieci
Operator new dynamicznie rezerwuje pamięć na tworzony obiekt.
Można się zastanowić jak obiekty są niszczone a ich pamięć
zwalniana.
W niektórych językach (np. C++) obiekty zarezerwowane dynamicznie
muszą być zwalniane ręcznie poleceniem delete (lub podobnym).
W Java przyjęto inne rozwiązanie. JVM posiada mechanizm zwany
zbieraczem śmieci (ang.: garbage collection), który
automatycznie zwalnia pamięć przydzieloną obiektom, do których
brak jakichkolwiek odwołań.
Zbieracz śmieci włącza się sam, gdy jest co posprzątać.
Nie ma jednej reguły jego włączania i wyłączania się.
Różne JVM posiadają różne algorytmy zbierania śmieci, lecz mają
jedną wspólną cechę: programista nie musi pamiętać o zwalnianiu
pamięci, jak i o samym zbieraczu śmieci.
7
Metoda finalize
Ze zbieraczem śmieci związana jest metoda finalize. Zbieracz
śmieci zaraz przed zwolnieniem obiektu uruchamia metodę finalize
zwalnianego obiektu.
Metoda ta jest stosowana, gdy obiekt rezerwuje pewne nie-Javowe
zasoby, które muszą być zwolnione w specjalny sposób, np:
deskryptory plików, czy fonty.
Na metodzie tej nie możemy opierać poprawności implementowanego
algorytmu, ponieważ nie wiemy, kiedy zostanie wywołana przez
zbieracz śmieci.
Postać metody:
protected void finalize() {
// tu kod metody
}
8
Przeciążanie metod
W Java możemy definiować wiele metod o tej samej nazwie w obrębie
jednej klasy. Metody takie nazywamy przeciążonymi. Muszą one
różnić się typami i/lub liczbą argumentów. Mogą także różnić się
typami wynikowymi ale nie wystarcza to by metody były różne.
Zobacz: OverloadDemo.java
Metody przeciążone wspierają polimorfizm.
W językach nie pozwalających na przeciążanie metod/funkcji często
dla wyrażenia podobnych operacji dla różnych typów wejściowych
trzeba używać różnych nazw. Np. w C funkcja abs() zwraca wartość
bezwzględną liczby całkowitej, labs() długiej liczby całkowitej,
fabs() liczby rzeczywistej, ... .
W Java dzięki przeciążaniu metod można zdefiniować jedną nazwę
metody działającą na różnych typach.
Zobacz: AbsDemo.java
W podobny sposób jak zwykłe metody, możemy przeciążać także
konstruktory (patrz ponownie na przykład BoxDemo3.java)
9
Przekazywanie parametrów
Obiekty jako parametry metod. Ponieważ klasy w Java są
traktowane jak typy w tradycyjnych językach programowania, to
można przekazywać obiekty (parametry typu klasowego) do metod i
zwracać obiekty jako wartości.
Zobacz: ParameterDemo.java
Przekazywanie parametrów metod przez wartość i zmienną.
W Java sposób przekazywania parametrów do metody zależy od ich
typu. Parametry typów prostych zawsze są przekazywane przez
wartość, natomiast przekazywanie obiektów do metod zawsze odbywa
się przez zmienną.
Przyponienie pojęć:
 Przekazywanie przez wartość: przekazywane wartości nie ulegają
trwałym zmianom - po wywołaniu metody wartość jak przed
 Przekazywanie przez zmienną: przekazywane wartości ulegają
trwałym zmianom - po wywołaniu metody wartość się zmienia
Zobacz: CallByDemo.java
10
Kontrola dostępu
Klasy definiowane dotychczas nie posiadały ważnej cechy
programowania obiektowego: hermetyzacji, tj. oddzielenia świata
zewnętrznego od danych klasy (patrz Stack.java).
Java pozwala na kontrolę dostępu na poziomie pakietu, klasy i
komponentu klasy. Realizowana jest ona za pomocą słów kluczowych
(specyfikacji kontroli dostępu):
 public elementy są dostępne dla dowolnego innego kodu programu
także spoza klasy
 private dla elementu klasy sprawia, że jest on dostępny tylko dla
innych elementów tej samej klasy
 protected ma zastosowanie w procesie dziedziczenia klas
(omówimy później)
Domyślną specyfikacją kontroli dostępu, tj. gdy nic nie
wyspecyfikowano, jest public.
Zobacz: AccessDemo.java i Stack2.java
11
Elementy static
Zobacz: Static1.java i
Static2.java
Zwykle by móc używać elementów zdefiniowanych w klasie, musimy
najpierw utworzyć obiekt będący instancją danej klasy. Istnieje jednak
możliwość zdefiniowania elementów, do których nie musimy się
odwoływać za pośrednictwem obiektów. Do wyróżnienia takich
elementów służy słowo kluczowe static. Typowym przykładem jest
metoda main(). static może być stosowane do:
 Zmiennych instancji: są one wówczas zmiennymi globalnymi
wszystkich obiektów danej klasy. Utworzenie obiektu danej klasy nie
powoduje powstania statycznej zmiennej instacji.
 Metod: podlegają one następującym restrykcjom:
Mogą wywoływać tylko inne metody statyczne
 Mogą korzystać wyłącznie ze zmiennych statycznych
 Nie mogą odwoływać się do zmiennych this i super
Jeżeli trzeba wykonać obliczenia by zainicjalizować zmienne
statyczne, można zdefiniować blok static. Będzie on wykonany tylko
raz, gdy klasa jest po raz pierwszy załadowana.

12
Elementy final
Słowo kuczowe final służy do oznaczenia zmiennych, których
wartość ma być niezmienna we wszystkich instancjach. Pełnią one
rolę stałych i muszą być inicjalizowane przy deklaracji. Przykłady:
final int FILE_NEW = 1;
final int FILE_OPEN = 2;
final int FILE_SAVE = 3;
final int FILE_QUIT = 4;
Dalsza część programu może używać powyższych zmiennych jak
stałych. Dodatkowo nie zajmują one miejsca w instancjach klasy.
Przyjętą konwencją jest pisanie zmiennych final dużymi literami.
Słowo kuczowe final może również być zastosowane do metod, lecz
znaczenie takiego zastosowania jest zupełnie inne niż w przypadku
zmiennych. Zastosowanie final do metod wyjaśnimy podczas
omawiania dziedziczenia klas.
13
Tablice
Omawiając tablice nie wspomnieliśmy, że są one implementowane
jako obiekty. Jako obiekty posiadają specjalny atrybut length
reprezentujący liczbę elementów jakie tablica może przechowywać
(a nie ich aktualną liczbę).
class Length {
public static void main(String args[]) {
int a1[] = new int[10];
int a2[] = {1, 2, 3, 4, 5, 6, 7, 8};
int a3[] = {4, 3, 2, 1};
int c = a1.length + a2.length + a3.length;
System.out.println(c);
}
}
Wynik: 22
Zobacz: Stack3.java
14
Klasy wewnętrzne
Zobacz: Inner1.java
Inner2.java
W Java istnieje możliwość definiowania klasy wewnątrz innej klasy.
Klasy takie nazywa się klasami zagnieżdżonymi. Zakres klasy
wewnętrznej jest ograniczony klasą zewnętrzną, tj.:
Jeżeli klasa B jest zdefiniowana wewnątrz klasy A, wówczas B
jest znana wewnątrz A, natomiast nie jest poza A.
Klasa wewnętrzna posiada dostęp do wszystkich elementów klasy
zewnętrznej (nawet prywatnych), natomiast klasa zewnętrzna nie
posiada dostępu do elementów klasy wewnętrznej.
Istnieją dwa rodzaje klas wewnętrznych:
 Statyczne: zdefiniowane ze słowem kluczowym static. Nie mogą
odwoływać się one do elementów klasy zewnętrznej (niestatycznej)
wprost. Muszą zdefiniować obiekt klasy zewnętrznej i odwoływać się
za jego pośrednictwem; rzadko używane.
 Niestatyczne: najczęściej używane. Mają dostęp do wszystkich
elementów klasy zewnętrznej tak jak jej metody niestatyczne
15
Klasa String
Zobacz: StringDemo.java
Klasa String jest prawdopodobnie najczęściej używaną klasą języka
Java, ponieważ każdy napis używany w programie jest obiektem klasy
String. Dotyczy to także napisów stałych, np.:
System.out.println(“To jest napis”);
Napis “To jest napis” jest obiektem klasy String.
Obiekty klasy String są niezmienne, tj. raz utworzone nie mogą
zmieniać swojej zawartości. Jeżeli chcemy zmienić zawartość napisu,
trzeba utworzyć nowy zmodyfikowany.
W Java istnieje także klasa StringBuffer pozwalająca na
dokonywanie zmian w przechowywanych napisach.
Obiekty klasy String posiadają metody (m.in.)
 boolean equals(String o) równość dwóch napisów
 int length() długość napisu
 char charAt(int i) znak na pozycji i
16
Parametry linii komend
W Java, pododnie jak w innych językach programowania, istnieje
możliwość przekazania parametrów wywołania programu do metody
main(). Parametry te są przekazane do programu jako tablica
elementów typu String. Następujący program wypisuje wszystkie
argumenty, z którymi został wywołany:
class CommandLine {
public static void main(String args[]) {
for(int i = 0; i < agrgs.length; i++)
System.out.println(“arg[“ + “] =” +
args[i]);
}
}
Przykładowe wywołanie:
$ java CommandLine to tylko test
Zobacz jak działa: CommandLine.java
17

Podobne dokumenty