wprw1.doc

(255 KB) Pobierz
Obiektowość Javy

Autor wykładu:

Krzysztof Barteczko

Obiektowość Javy

 

 

 

 

(agenda)

 

 

1.      PODSTAWOWE DEFINICJE

2.      ABSTRAKCJA OBIEKTOWA. KLASY I OBIEKTY

3.      HERMETYZACJA

4.      STATYCZNE SKŁADOWE KLASY

5.      INICJALIZACJA ELEMENTÓW OBIEKTÓW

6.      PRZECIĄŻANIE METOD i KONSTRUKTORÓW

7.      PEŁNY PRZYKŁAD klasy Vehicle i jej wykorzystania

8.      DZIEDZICZENIE

9.      OBIEKTOWE KONWERSJE ROZSZERZAJĄCE

10.  POLIMORFIZM. METODY WIRTUALNE

11.  ZNACZENIE POLIMORFIZMU

12.  METODY I KLASY ABSTRAKCYJNE

13.  INTERFEJSY

14.  ADAPTERY

15.  KONWERSJE OBIEKTOWE W DÓŁ

16.  KLASY WEWNĘTRZNE

17.  ANONIMOWE KLASY WEWNĘTRZNE

18.  WEWNĘTRZNE KLASY LOKALNE

 

 

 

 

 

 

 


PODSTAWOWE DEFINICJE

 

Java  jest językiem obiektowym. Języki obiektowe posługują się pojęciem obiektu i klasy.

 

Obiekt – to konkretny lub abstrakcyjny byt, wyróżnialny w modelowanej rzeczywistości, posiadający określone granice i atrybuty (właściwości) oraz mogący świadczyć określone usługi.

 

Usługa – to określone działanie (zachowanie) obiektu, które jest on zobowiązany przejawiać.

 

Obiekty współdziałają ze sobą wymieniając komunikaty.

Komunikat -  to wąski i dobrze określony interfejs, opisujący współzależność działania obiektów. Komunikaty zwykle żądają od obiektów wykonania określonych (właściwych im) usług.

 

Klasa - to opis takich cech grupy podobnych obiektów, które są dla nich niezmienne (np. zestaw atrybutów i metod czyli usług, które mogą świadczyć)

 

Definicje powyższe stanowią abstrakcyjne odzwierciedlenie cech rzeczywistości.

 

ABSTRAKCJA OBIEKTOWA. KLASY I OBIEKTY

Gdybyśmy mieli w języku programowania podobne pojęcia, to moglibyśmy ujmować projekt rozwiązania rzeczywistego problemu i jego oprogramowanie w języku adekwatnym do problemu. I to zapewniają języki obiektowe. Jest to ich bardzo ważna cecha – abstrakcja obiektowa, znacznie ułatwiająca tworzenie oprogramowania.

 

Programowanie polega na przetwarzaniu danych. Dane zawsze są określonych typów, a typ to nic innego jak rodzaj danych i działania które na nich można wykonać.

Z pragmatycznego punktu widzenie możemy więc powiedzieć, że klasa to typ, jej definicja opisuje właściwości typu danych (również funkcjonalne tzn. jakie są dostępne operacje na danych tego typu).

Języki obiektowe pozwalają na definiowanie własnych klas – własnych typów danych, co właśnie oznacza programowanie w języku problemu.

O obiektach możemy myśleć jako o egzemplarzach określonych klas.

 

 

 

Możemy mieć np. klasę pojazdów o następujących atrybutach: szerokość, wysokość, długość, ciężar, właściciel,  stan (stoi, jedzie, zepsuty itp.)  oraz udostępniających usługi: ruszania, zatrzymywania, zmiany właściciela (sprzedaż pojazdu) itp .

Atrybuty obiektów klasy.

Pola klasy

class Vehicle  {

Pola

+

metody

=

składowe

klasy



 

  int width, height, length, weight;

  Person owner; // referencja do obiektu klasy Person

  int state;   // aktualny stan pojazdu

 

============================= INTERFEJS KOMUNIKATÓW

Metody (inaczej: funkcje).

Interfejs jest zestawem metod.

 

  void start()  { // uruchomienie pojazdu }



  void stop()  { // zatrzymanie pojazdu  }

  void repair()  { // reperowanie pojazdu }

  void sellTo(Person p)  { // sprzedaż pojazdu }

}

 

Gdy mamy np. dwa obiekty – egzemplarze klasy pojazdów, oznaczane przez zmienne a i b, to możemy symulować w programie sekwencję działań: uruchomienie pojazdu a, uruchomienie pojazdu b, zatrzymanie obu pojazdów - za pomocą komunikatów posyłanych do obiektów, np.:

a.start();       // komunikat do pojazdu a: ruszaj!
b.start();       // komunikat do pojazdu b: ruszaj!

a.stop();       // komunikat do pojazdu a: zatrzymaj się!

b.stop();       // komunikat do pojazdu b: zatrzymaj się!

 

Mówi się również: a.start()  - to użycie metody start() na rzecz obiektu oznaczanego przez zmienną a.

 

HERMETYZACJA

Oprócz odzwierciedlenia w programie "języka problemu" abstrakcja obiektowa ma jeszcze jedną ważną przewagę nad ujęciami nieobiektowymi.

Mianowicie, atrybuty obiektu nie powinny być bezpośrednio dostępne. W programie z obiektami "rozmawiamy" za pomocą komunikatów, obiekty same "wiedzą najlepiej" jak zmieniać swoje stany. Dzięki temu nie możemy nic nieopatrznie popsuć, co więcej nie możemy zażądać od obiektu usługi, której on nie udostępnia.

Dane (atrybuty) są ukryte i są traktowane jako nierozdzielna całość z usługami.

Nazywa się to hermetyzacją (enkapsulacją) i oznacza znaczne zwiększenie odporności programu na błędy.

 

Sama koncepcja klasy jako zestawu pól i metod już zapewnia określony poziom hermetyzacji.

Nie możemy np. do obiektów klasy Vehicle posłać komunikatu sing(), bowiem metoda sing() nie występuje jako składowa tej klasie.

Dodatkowo języki obiektowe (w tym Java) pozwalają ukrywać dane (i metody)  przed powszechnym dostępem.

Dostęp do składowych klasy regulują tzw. specyfikatory dostępu, których używamy w deklaracjach zmiennych, stałych i metod.

Każda składowa klasy może być:

·         prywatna – dostępna tylko w danej klasie (specyfikator private)

·         zaprzyjaźniona – dostępna ze wszystkich klas danego pakietu; mówi się tu też o dostępie pakietowym lub domyślnym- domyślnym dlatego, iż ten rodzaj dostępności występuje wtedy, gdy w deklaracji składowej nie użyjemy żadnego specyfikatora.

·         chroniona lub zabezpieczona – dostępna z danej klasy i wszystkich klas ją dziedziczących (specyfikator protected)

·         publiczna – dostępna zewsząd (specyfikator public)

 

Po co jest prywatność? 

1. Ochrona przed zepsuciem (pola powinny być prywatane)

użytkownik klasy nie ma dostępu do prywatnych pól i nic nie popsuje (nieświadomie)

2.  Zapewnienie właściwego interfejsu  (metody "robocze" winny być prywatne)

użytkownik klasy ma do dyspozycji tylko niezbędne (klarowne) metody, co ułatwia mu korzystanie z klasy

3. Ochrona przed konsekwencjami zmiany implementacji

Mamy też w Javie pojęcie klas publicznych i pakietowych (klasy w Javie są albo publiczne albo pakietowe).Klasa pakietowa jest dostępna tylko z klas pakietu .Klasa publiczna jest dostępna zewsząd (z innych pakietów).Klasę publiczną deklarujemy ze specyfikatorem public

 

twórca klasy może zmienić zestaw i implementację prywatnych metod, nie zmieniając interfejsu publicznego: wszystkie programy napisane przy wykorzystaniu tego interfejsu nie będą wymagały żadnych zmian

 

Stosując regułę ukrywania danych i specyfikatory dostępu możemy teraz przedstawić przykładową definicję klasy Person, a następnie zmodyfikować definicję klasy Vehicle.


public class Person  {

 

   private String name;

Konstruktor.

Ma taką samą nazwę jak klasa i nie ma żadnego typy wyniku.

Zwykle służy do inicjalizacji obiektów,  ich elementów, odpowiadających polom klasy

   private String pesel;



  

   public Person(String aname, String id)  {

       name = aname;

       pesel = id;

   }

  

   public String getName()  { return name; }

   public String getPesel()   { return pesel; }

}

 

Atrybuty obiektów klasy Person przedstawiono jako pola prywatne.

Spoza klasy nie ma do nich dostępu.

Przy tworzeniu obiektu jego elementy odpowiadające tym polom są inicjalizowane za pomocą wywołania konstruktora. Później zmiany tych elementów danych nie są już możliwe, możemy tylko uzyskać dane za pomocą publicznych metod getName() i getPesel().

 

Przypomnienie

·         programowanie w Javie polega na posługiwaniu się obiektami

·         przed użyciem obiekty muszą być tworzone

·         do tworzenia obiektów służy wyrażenie new

·         po słowie new podajemy odwołanie do konstruktora z odpowiednimi argumentami

·         wyrażenie new zwraca referencję (odniesienie, swoisty adres) do nowoutworzonego obiektu

·         posługiwanie się obiektami w Javie polega wyłącznie na operowaniu na referencjach

 

String name = new String("Jan Kot");  // String klasa łańcuchów znakowych (napisów)

Zatem po:

String name = "Jan Kot";      // TYLKO dla klasy String 

String pesel = "020289098"  // ten same efekt co użycie

                                               // new String(...)

Person p = new Person(name, pesel);

 

zmienna p jest referencją do nowoutworzonego obiektu klasy Person, który został za pomocą konstruktora Person(String, String) zainicjalizowany dwoma referencjami do obiektów typu String.





 

name



1789

 

 

Obiekty na stercie

...

 

1789

Jan Kot

...

 

Terminologia

 

"Adres" obiektu nazywa się odniesieniem. Zmienna, która zawiera odniesienie nazywa się odnośnikiem.

Często nie rozgranicza się tych dwóch pojęć i mówi się o odniesieniu i odnośniku jako o referencji. Jest to czasem wygodniejsze, szczególnie, gdy różnica treści zawsze jasna jest z kontekstu.

Dla wygody używać będziemy także skrótu myślowego mówiąc o obiektach, gdy naprawdę chodzi o referencje np. zamiast "metoda zwraca referencję do obiektu klasy Color" – "metoda zwraca obiekt" lub nawet "zwraca kolor".  Pamiętajmy jednak zawsze, że w Javie operuje się wyłącznie na referencjach.

 

 

 

 

 

 

 

Modyfikując i rozbudowując klasę Vehicle w myśl reguł hermetyzacji:

·         uczynimy atrybuty pojazdów prywatnymi

·         dostarczymy – jako publicznego – tylko niezbędnego interfejsu

·         ukryjemy "roboczą" metodę zmieniającą stan obiektu

·         wprowadzimy publiczne stałe oznaczające stany pojazdu oraz odpowiadające im nazwy stanów (które uczynimy prywatnymi, by ew. zmiany nazw nie wpływały na oprogramowanie wykorzystujące klasę Vehicle)

 

public class Vehicle  {

Do definiowania stałych służy słowo kluczowe final

  // stany

  public final  int BROKEN = 0, STOPPED = 1, MOVING = 2;

  private final String[] states =  { "ZEPSUTY", "STOI", "JEDZIE" };

 

  private int width, height, length, weight;

  private Person owner;

  private int state;

 

  public Vehicle(Person p, int w, int h, int l, int ww)  {  // konstruktor

     owner = p;      width = w;     height = h;   

     length = l;     weight = ww;     state = STOPPED;

  }

 

  public void start()  {     setState(MOVING);  }

 

  public void stop()  {     setState(STOPPED);  }

 

// Prywatna metoda robocza wykorzystywana w metodach start() i stop().

// Arbitralne ustalenie stanu spoza klasy nie jest możliwe

  private void setState(int newState)  {

     if (state == newState || state == BROKEN) 

        System.out.println("Nie jest mozliwe przejscie ze stanu " +

                                        states[state] + " do stanu " + states[newState]);

     else state = newStat...

Zgłoś jeśli naruszono regulamin