(c) Krzysztof Barteczko 2014

Slides:



Advertisements
Podobne prezentacje
Wstęp do strumieni danych
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
Programowanie obiektowe
Klasy abstrakcyjne i interfejsy
Deklaracje i definicje klas w C++ Składowe, pola, metody Konstruktory
Programowanie obiektowe
Klasy i obiekty.
Metody wirtualne.
Wzorce.
Static, const, volatile.
Dziedziczenie. Po co nam dziedziczenie? class osoba { char * imie, char * imie, * nazwisko; * nazwisko;public: void wypisz_imie(); void wypisz_imie();
Generics w .NET 2.0 Łukasz Rzeszot.
Mapowanie dziedziczenia z UML do Java
Programowanie Obiektowe w Javie (c.d.)
Nguyen Hung Son Uniwersytet Warszawski
Programowanie obiektowe w Javie
OOP - programowanie zorientowane obiektowo w VB.NET
Serwery Aplikacji ASP .NET Web Objects Arkadiusz Popa.
W ZORCE P ROJEKTOWE … czyli ktoś już rozwiązał Twoje problemy!
Obiektowe metody projektowania systemów
C++ wykład 2 ( ) Klasy i obiekty.
Zasady zaliczenia Warunki uzyskania zaliczenia:
Typy pochodne 1 Często dogodnie jest wprowadzić nowy typ, który jest podobny do istniejącego, niemniej jednak różny. Niech T będzie pewnym typem. Możemy.
Czytanie, pisanie i rysowanie – cd.. Jeszcze jeden strumyk PrintStream działa jak PrintWriter, ale: Używa domyślnego (systemowego) kodowania Nie wyrzuca.
Język Java Wielowątkowość.
T: Różnice pomiędzy programowaniem strukturalnym a obiektowym
C# cz.3 Obiektowość w C# Krzysztof Fediuk
Tworzenie aplikacji mobilnych
JAVA c.d.. Instrukcji wyboru SWITCH używamy, jeśli chcemy w zależności od wartości pewnego wyrażenia wykonać jeden z kilku fragmentów kodu. Jest to w.
Andrzej Repak Nr albumu
Java – coś na temat Klas Piotr Rosik
Dziedziczenie Maciek Mięczakowski
Inicjalizacja i sprzątanie
INTERFEJSY I KLASY WEWNĘTRZNE
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 7 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/20 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Programowanie obiektowe – język C++
Programowanie obiektowe 2013/2014
  ELEMENTY JĘZYKA JAVA komentarze w Javie, słowa kluczowe i operatory, proste typy danych, tablice, podstawowy zestaw instrukcji.
Kurs języka C++ – wykład 9 ( )
Programowanie w języku C++
Diagram klas Kluczowymi elementami są: klasy (class)
Kurs języka C++ – wykład 4 ( )
Programowanie obiektowe Wykład 9 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/15 Dariusz Wardowski.
Model współbieżności w Javie
Programowanie Zaawansowane
Dziedziczenie Wykład 7 Dziedziczenie sekwencyjne
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
Statyczna kontrola typów w SBQL Rafał Hryniów Polsko-Japońska Wyższa Szkoła Technik Komputerowych, Warszawa
Podstawy informatyki Funkcje Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Kolekcje (3) Zbiory. Porównywanie i porządkowanie elementów kolekcji. (c) Krzysztof Barteczko 2014.
1 Wprowadzenie: Języki programowania. Java i języki JVM © Krzysztof Barteczko, PJWSTK
Elementy programowania funkcyjnego w Javie 8. Pragmatyczny przegląd. (c) Krzysztof Barteczko 2014.
Typy i metody sparametryzowane (generics) (c) Krzysztof Barteczko 2014.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
Podstawowe konstrukcje języka Java Bartosz Walter InMoST Wielkopolska sieć współpracy w zakresie innowacyjnych metod wytwarzania oprogramowania Termin.
Programowanie Obiektowe – Wykład 6
Wątki, programowanie współbieżne
(według:
Ponowne wykorzystanie klas
Delegaty Delegat to obiekt „wiedzący”, jak wywołać metodę.
Programowanie Obiektowe – Wykład 2
Klasy wewnętrzne. Praktyka użycia interfejsów i klas wewnętrznych
PGO Interfejsy Michail Mokkas.
PGO Dziedziczenie Michail Mokkas.
Zapis prezentacji:

(c) Krzysztof Barteczko 2014 Interfejsy (c) Krzysztof Barteczko 2014

Metody i klasy abstrakcyjne Metody abstrakcyjne - nie wiemy jeszcze jaka może być ich konkretna implementacja, ale wiemy, że powinny wystąpić w zestawie metod każdej konkretnej klasy dziedziczącej klasę abstrakcyjną. Konkretna implementacja (definicja kodu metody) może być bardzo różna, w zależności od konkretnego rodzaju obiektów, które opisuje dana klasa. Klasa abstrakcyjna nie musi mieć metod abstrakcyjnych. Wystarczy zadeklarować ją ze specyfikatorem abstract. Nie wolno tworzyć obiektów klas abstrakcyjnych. (c) Krzysztof Barteczko 2014

Przykład – abstrakcyjne metody Polimorficzne odwołania do nieistniejących być może metod (c) Krzysztof Barteczko 2014

Implementacja metod abstrakcyjnych (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Pojęcie interfejsu (c) Krzysztof Barteczko 2014

Problem wielodziedziczenia (1) Nie wszystkie zwierzęta wydają głos. Zatem umieszczanie (abstrakcyjnej) metody getVoice() oraz metody speak()  w klasie Zwierz  nie jest "czystym rozwiązaniem". Co więcej nie tylko zwierzęta mówią. Chciałoby się więc mieć klasę obiektów wydających głos, którą mógłby dziedziczyć np. Wodospad i Pies. Ale Pies jest Zwierzem (dziedziczy Zwierza) i nie może odziedziczyć klasy obiektów "wydających głos". W Javie nie ma bowiem  wielodziedziczenia klas: każda klasa może dziedziczyć bezpośrednio tylko jedną klasę. (c) Krzysztof Barteczko 2014

Dlaczego w Javie nie ma wielodziedziczenia klas abstract class Human {     public abstract String getSex(); } class Father extends Human {     public String getSex() { return "male"; } } class Mother extends Human {     public String getSex() { return "female"; } } // hipotetyczne wielodziedziczenie class Child extends Mother, Father  {     // klasa Child nie przedefiniowuje metody getSex() ! } class A {    public int a; } class B extends A {   // ma pole a } class C extends A {  //  ma pole a } // hipotetyczne wielodziedziczenie class D extends B i C { } jaki wynik dla obiektu-dziecka (klasy Child) zwróci wywołanie metody getSex() ? Obiekt d z klasy D ma element definiowany przez pole a. Jeden czy dwa? Jeśli jeden, to który? Poczynając od Java wersja 8 mamy możliwość wielodziedziczenia konkretnych implementacji metod (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Interfejsy na pomoc (c) Krzysztof Barteczko 2014

Interfejsy – definicja i implementacja (c) Krzysztof Barteczko 2014

Można implementować wiele interfejsów (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Nowy Zwierz i nowy Pies public class Pies extends Zwierz implements Speakable, Moveable { public Pies() {} public Pies(String s) { super(s); } public String getTyp() { return "Pies"; public String getVoice(int voice) { if (voice == LOUD) return "HAU... HAU... HAU... "; else return "Hau... Hau..."; public Pies start() { System.out.println("Pies " + getName() + " biegnie"); return this; public Pies stop() { System.out.println("Pies " + getName() + " stanął"); public Pies merda() { System.out.println("Merda ogonem"); Zmieniając nieco definicję klasy Zwierz (nie wszystkie zwierzęta wydają głos, więc usunęliśmy metody getVoice() i speak()): public abstract class Zwierz { private String name = "bez imienia"; public Zwierz() {} public Zwierz(String s) { name = s; } public abstract String getTyp(); public String getName() { return name; Możemy teraz tak zdefiniować klasę Pies Używana dalej klasa Kot jest zdefiniowana podobnie. (c) Krzysztof Barteczko 2014

Interfejsy też wyznaczają typy (c) Krzysztof Barteczko 2014

Jeśli interfejsy wyznaczają typy, to ... Możemy:  wykonywać konwersje w górę do typu wyznaczanego przez implementowany interfejs,  używać operatora instanceof,  by stwierdzić czy obiekt jest obiektem klasy implementującej dany interfejs. Implementacja interfejsów działa podobnie jak przedefiniowanie metod: zauważmy, że metody start() i stop() interfejsu Moveable mają typ wyniku Moveable. W klasie Pies implementowaliśmy je z typem wyniku Pies, czyli przy implementacji interfejsów dopuszczalna jest kowariancja typów wyniku implementowanych metod. (c) Krzysztof Barteczko 2014

Polimorfizm przy użyciu interfejsów public class Vehicle implements Moveable { // ... public Vehicle start() { setState(MOVING); return this; } public Vehicle stop() { setState(STOPPED); Dzięki interfejsom polimorficzne odwołania są możliwe nie tylko "wzdłuż" hierarchii dziedziczenia klas, ale również "w poprzek" tych hierarchii. Klasy Pies i Kot należą do innej hierarchii dziedziczenia niż klasa Car i Rower. Dzięki temu, że wszystkie te klasy implementują interfejs Moveable dla wszystkich tych klas uzyskujemy możliwość polimorficznych odwołań do metody start(). public class Wyscig { static void wyscig(Moveable ... moveables) { for (Moveable m : moveables) { m.start(); if (m instanceof Vehicle) System.out.println(m); } public static void main(String[] args) { wyscig(new Pies("Kuba"), new Car("WB4545", new Person("Janek", "9012102567"),100, 100, 100, 100, 100).fill(10), new Kot("Mruczek"), new Bicycle(new Person("Ala", "7011122347"),100, 100, 100, 100) ); Pies Kuba biegnie Samochód nr rej WB4545 - JEDZIE Kot Mruczek się skrada Pojazd 2, właścicielem którego jest Ala jest w stanie JEDZIE (c) Krzysztof Barteczko 2014

Mechanizm konwersji zawężających Konwersje zawężające Przypomnienie: jeśli mamy referencję do obiektu typu Zwierz na którą podstawiono odniesienie do obiektu typu Pies, to możemy zrobić konwersję "w dół" hierarchii dziedziczenia.      Pies p = new Pies();     Zwierz z = p;     Pies p1 = (Pies) z; // Konwersja z typu Zwierz do typu Pies Mówiąc obrazowo (ale pamiętając o tym, że mamy do czynienia z konwersjami referencyjnymi i tak naprawdę jest tu tylko jeden obiekt, który po prostu, w kolejnych przekształceniach referencyjnych, traktujemy inaczej):  Pies pochodzi od Zwierza, możemy więc z Psa uzyskać Zwierza, a później z tego Zwierza z powrotem Psa. Mechanizm konwersji zawężających w równym stopniu dotyczy interfejsów. (c) Krzysztof Barteczko 2014

Konwersje referencyjne - przykład (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 ... przykład c.d. dla obiektu hipotetycznej klasy Ryba - info( new Ryba()) - możemy dostać w wyniku tylko: public class Ryba extends Zwierz implements Moveable { public Ryba() { super(""); } public Ryba(String s) { super(s); @Override public String getTyp() { return "Ryba"; public Moveable start() { System.out.println("płynie"); return this; public Moveable stop() { System.out.println("śpi"); Ryba Bo wartość wyrażenia z instanceof Speakable jest false (Ryba nie implementuje interfejsu Speakable) i oczywiście nie jest też Psem. Natomiast  dla Psa kuby (kuba = new Pies("Kuba")) po info(kuba) dostaniemy pewnie: Pies Kuba HAU... HAU... HAU... Merda ogonem (c) Krzysztof Barteczko 2014

Konwersje referencyjne – przykład 2 Przywróćmy w klasie Zwierz metodę speak() public void speak(int ... v) { int vol = Speakable.QUIET; if (v.length == 1) vol = v[0]; String voice; if (this instanceof Speakable) voice = ((Speakable) this).getVoice(vol); else voice = "... (cisza) ..."; System.out.println(getTyp()+" "+getName()+ " mówi " + voice); } static void animalDialog(Zwierz z1, Zwierz z2) { z1.speak(); z2.speak(); System.out.println("--------------------------------------"); } // ... Pies kuba = new Pies("Kuba"), reksio = new Pies("Reksio"); Kot kot = new Kot("Mruczek"); Ryba ryba = new Ryba(); animalDialog(kuba, reksio); animalDialog(kuba, kot); animalDialog(reksio, ryba); Pies Kuba mówi Hau... Hau... Pies Reksio mówi Hau... Hau... -------------------------------------- Kot Mruczek mówi Miau... Ryba bez imienia mówi ... (cisza) ... (c) Krzysztof Barteczko 2014

Implementacje metod w interfejsach W Javie 8 wprowadzono możliwość dostarczania gotowych definicji metod w interfejsach (publicznych metod statycznych oraz publicznych niestatycznych metod z użyciem słowa kluczowego default). Istotą tych zmian jest umożliwienie rozbudowy już istniejących interfejsów w taki sposób, by nie zakłócić zgodności z klasami, które już implementują te interfejsy. Rzeczywiście, do interfejsów, które już zostały zaimplementowane przez jakieś klasy nie powinniśmy dodawać metod abstrakcyjnych, bowiem w takim przypadku klasy te przestaną działać i będą wymagać zmian w kodzie - implementacji nowych metod interfejsu. Z drugiej strony czasem dodanie do istniejącego interfejsu nowych metod byłoby wskazane. Oczywiście, to nie mogą być metody abstrakcyjne. (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Przykład (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Mixiny (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Mixiny w użyciu (c) Krzysztof Barteczko 2014

Co teraz z rombem wielodziedziczenia ? (c) Krzysztof Barteczko 2014

Metody domyślne można przedefiniowywać i przeciążać class Child implements Mother, Father { public String getSex() { return "?"; } public String fatherName() { return "Tata: Jan"; } public String motherName() { return "Mama: Ala"; } public String fatherName(int age) { return "Jan, lat " + age; } public String toString() { return "Rodzice - " + fatherName() + " " + motherName(); } // ... Child child = new Child(); System.out.println(child); System.out.println(child.fatherName(30)); Rodzice - Tata: Jan Mama: Ala Jan, lat 30 (c) Krzysztof Barteczko 2014

Domyślne metody są polimorficzne interface BaseIf { default String get() { return this.getClass().getSimpleName(); } //brak abstrakcyjnych metod do implementacji! class A implements BaseIf {} class B implements BaseIf {} public class WhatIsThis { public static void main(String[] args) { BaseIf a = new A(); System.out.println(a.get()); BaseIf b = new B(); System.out.println(b.get()); A B (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 A jak użyć super ? class Child implements Mother, Father { public String getSex() { return "?"; } public String fatherName() { return "Tata: " + Father.super.fatherName(); } public String motherName() { return "Mama: " + Mother.super.motherName(); } public String toString() { return "Rodzice - " + fatherName() + " " + motherName(); } // ... Child child = new Child(); System.out.println(child); Rodzice - Tata: Jan Mama: Ala (c) Krzysztof Barteczko 2014

(c) Krzysztof Barteczko 2014 Jeszcze raz: kolizje Gdy te same domyślne metody w kilku implementowanych interfajsach – wystąpi błąd w kompilacji (romb wielodziedziczenia). (c) Krzysztof Barteczko 2014

Różne implementacje tych samych metod Jeśli ta sama metoda domyślna jest implementowana na różnych poziomach hierarchii dziedziczenia, to:  priorytet ma metoda przedefiniowana w klasie obiektu,  jeśli jej nie ma, to metoda implementowana w nadklasie obiektu, jeśli jej nie ma, to metoda najbliższego w hierarchii interfejsu interface IfA { default void m() { System.out.println("Z IfA"); } } interface IfB extends IfA { default void m() { System.out.println("Z IfB"); } class A implements IfA, IfB { } class B implements IfA, IfB { public void m() { System.out.println("Z B"); class C extends B implements IfA, IfB {} // ... new A().m(); IfA b = new B(); b.m(); IfA c= new C(); c.m(); Z IfB Z B (c) Krzysztof Barteczko 2014

Nie nadużywać metod domyślnych Głównym przeznaczeniem metod domyślnych jest bezkolizyjne modyfikowanie istniejących interfejsów. Inne przypadki uzycia (mixiny) trzeba stosować z umiarem. W przeciwnym razie możemy nadmiernie skomplikować hierarchię dziedziczenia w programie. (c) Krzysztof Barteczko 2014