Pobierz Programowanie obiektowe i więcej Ćwiczenia w PDF z Programowanie obiektowe tylko na Docsity! Przygotował: Jacek Sroka 1 Programowanie obiektowe Wykład 4 – Java podstawy c.d. (w tym pakiety, polimorfizm, modyfikatory, klasy abstrakcyjne, interfejsy) Przygotował: Jacek Sroka 2 Kolokwium planujemy na 10 kwietnia w trakcie wykładu!!! Przygotował: Jacek Sroka 5 Zagadka public class ScopeTest { int x; void test1() { x = x + 2; int x = 1; x = x++; System.out.println(x); System.out.println(this.x); } void test2(int x) { System.out.println(x); System.out.println(this.x); } public static void main (String[] args) { ScopeTest st = new ScopeTest(); st.test1(); st.test2(1); } } Przygotował: Jacek Sroka 6 !!! Przygotował: Jacek Sroka 7 Dziedziczenie i polimorfizm ● Dziedziczenie class Osoba { String imię = "Jan"; String nazwisko; void idźNaImprezę() {} } class Student extends Osoba { boolean niewyspany = false; void idźNaImprezę() { niewyspany = true; super.idźNaImprezę(); } void idźNaWykład() { niewyspany = false; } } ● Polimorfizm Osoba o = new Student(); o.idźNaImprezę(); Przygotował: Jacek Sroka 10 Polimorfizm ● Sprzeczne tendencje w programowaniu – Oprogramowanie ma być zamknięte: żeby inni nie zepsuli tego co już działa – Oprogramowanie ma być otwarte: żeby mogło się rozwijać jak się sprawdzi ● Możemy rozszerzać program/zrąb dodając nowe klasy i korzystając z zasady podstawialności ● Zachowujemy kontrolę typów przez kompilator ● Kod rozpoznający metody, których klas wykonać dostajemy za darmo i nie trzeba go uaktualniać ● Przykład Figura.rysuj(), Object.toString() Przygotował: Jacek Sroka 11 Przykład toString() i super class Osoba { private String imię, nazwisko; // ... @Override public String toString() { return "imię = " + imię + ", nazwisko = " + nazwisko; } } class Student extends Osoba { //String, aby numer mógł zawierać nie tylko cyfry (np. I-123456) private String nrIndeksu; //... @Override public String toString() { return super.toString() + ", nr indeksu = " + nrIndeksu; } } Przygotował: Jacek Sroka 12 super w konstruktorach class Osoba { public Osoba(String imię, String nazwisko){ this.imię = imię; this.nazwisko = nazwisko; } } class Student extends Osoba { public Student(String imię, String nazwisko, String nrIndeksu){ super(imię, nazwisko); this.nrIndeksu = nrIndeksu; } } class StudStypend extends Student { private int stypendium; public StudStypend(String imię, String nazwisko, String nrIndeksu, int stypedium){ super(imię, nazwisko, nrIndeksu); this.stypendium = stypedium; } @Override public String toString(){ return super.toString() + ", stypendium = " + stypendium; } } Przygotował: Jacek Sroka 15 Adapter ● Kontekst/Problem: Jak poradzić sobie z niekompatybilnymi interfejsami lub dostarczyć stabilny interfejs dla podobnych komponentów posiadających różniące się interfejsy? ● Rozwiązanie: Używając pośredniego obiektu adaptera przekształć oryginalny interfejs komponentu na inny. Dodajemy poziom pośredni składający się z obiektów, które przystosowują różnorodne zewnętrzne interfejsy do spójnego interfejsu używanego w aplikacji! Konwencja nazewnicza: nazwę wzorca wbudowujemy w nazwę typu Adaptery są Fasadami (opakowują dostęp do podsystemu lub systemu w pojedynczym obiekcie). Przygotował: Jacek Sroka 16 Fabryka ● Kto powinien tworzyć obiekty, np. obiekty (adaptery) reprezentujące zewnętrzne usługi (mogące mieć różne interfejsy, np. AdapterKartyVisa). ● Chcemy utrzymać rozdzielenie zagadnień – obiekty dziedzinowe odpowiadają jedynie za logikę aplikacji (chcemy zachować wysoką spójność). (Nie zawsze jest to możliwe – programowanie aspektowe). public NaszaFabryka { ... public AdapterKarty getAdapterKarty() { //odczytaj z pliku konfiguracyjnego jakiego adaptera użyć //utwórz odpowiedni i zwróć go } } Przygotował: Jacek Sroka 17 Singleton ● Jak uzyskać dostęp do fabryki z poprzedniego przykładu? ● Kto ją tworzy? ● Zazwyczaj potrzeba tylko jednej fabryki? ● Możemy przekazywać fabrykę jako parametr, ale możemy użyć wzorca Singleton public static synchronized NaszaFabryka getEgzemplarz() { // sekcja krytyczna, jeżeli aplikacja jest wielowątkowa if ( egzemplarz == null ) { egzemplarz = new FabrykaUsług(); } return egzemplarz; } //czyli fabryka staje się dostępna globalnie! ● egzemplarz jest atrybutem statycznym, a konstruktor fabryki jest prywatny Przygotował: Jacek Sroka 20 Pakiety ● Pomiędzy deklaracją pakietu i deklaracjami klas i interfejsów możemy wskazać jakich klas i interfejsów chcemy używać bez kwalifikowania ich nazw nazwą pakietu: import pak1.pak2.Klasa; import pak1.Interfejs; import pak1.*; //nie obejmuje podpakietów //java.lang.* jest importowane domyślnie ● JVM ładuje potrzebne klasy w chwili pierwszego odwołania, a odnajduje je dzięki wartości CLASSPATH (zmienna środowiska lub parametr wywołania) – java -cp … HelloWorld – Jeżeli CLASSPATH=/java:. to poszukiwany będzie plik /java/pak1/pak2/Klasa.class – jeżeli taki nie istniej to ./pak1/pak2/Klasa.class ● W CLASSPATH można też wskazać archiwum (jar lub zip) ● Nie znalezienie importowanej klasy/interfejsu powoduje błąd podczas kompilacji Przygotował: Jacek Sroka
GRAPH THEORY FOR GEEKS
AND THIS IS A
CLASSPATH7
21
Przygotował: Jacek Sroka 22 Pakiety c.d. Jeżeli pakiety pak1 i pak2 zawierają klasę A to: ● import pak1.A; import pak2.A; spowoduje błąd podczas kompilacji ● import pak1.*; import pak2.A; będzie poprawne i używana będzie A z pak2, chyba że A jest również definiowana w aktualnym pakiecie ● import pak1.*; import pak2.*; będzie poprawne, o ile nigdzie nie próbujemy odwoływać się do A lub definiujemy tą klasy w aktualnym pakiecie Przygotował: Jacek Sroka 25 Modyfikatory dostępu ● Dla atrybutów, metod, konstruktorów, klas i interfejsów – public (dostęp publiczny) – bez ograniczeń – protected (dostęp chroniony) – z pakietu i podklas (nawet w innym pakiecie) – brak modyfikatora (dostęp domyślny) – umożliwia dostęp z pakietu – private (dostęp prywatny) – z klasy zadeklarowanej na najwyższym poziomie struktury programu, w której jest zawarta (nie koniecznie bezpośrednio) deklaracja opatrzona tym modyfikatorem dostępu ● Dostęp do klasy pozwala: – tworzyć egzemplarze – rozszerzać – odwoływać się do atrybutów i metod, chyba że ich modyfikatory ograniczają ● Typ tablicowy dostępny jest wtedy i tylko wtedy, gdy dostępny jest typ elementów tablicy Przygotował: Jacek Sroka 26 Modyfikatory przykład ● Import się nie uda, bo klasa jest niewidoczna package po.egzamin.czerwiec; class Zadanie {} package po.egzamin.wrzesień; import po.egzamin.czerwiec.Zadanie class NoweZadanie extends Zadanie {} ● A tu już tak package po.egzamin.czerwiec; public class Zadanie {} package po.egzamin.wrzesień; import po.egzamin.czerwiec.Zadanie class NoweZadanie extends Zadanie {} ● Jak oznaczymy final, to public nie pomoże (ale się zaimportuje) Przygotował: Jacek Sroka 27 Klasy abstrakcyjne ● Klasy z niekompletną implementacją ● Nie można tworzyć ich egzemplarzy ● Przydają się jak chcemy wprowadzić wspólny kod do hierarchii abstract class PartiaPolityczna { void dzielIZwyciężaj() { //... generujTematZastępczy(); } abstract String generujTematZastępczy(); } class XYZ extends PartiaPolityczna { String generujTematZastępczy() { //... } } Przygotował: Jacek Sroka 30 Wielodziedziczenie ● Co ze składowymi odziedziczonymi z wielu nadklas? ● W Javie tylko jedna nadklasa ● W zamian za to interfejsy (klasy bardzo abstrakcyjne) – Zawierają jedynie sygnatury metod, bez implementacji (są abstrakcyjne i nie trzeba tego wskazywać) – Wszystkie metody są abstrakcyjne (czy to wskażemy czy nie) – Nie może być metod statycznych (ani final, strictfp, native) – Wszystkie składowe są publiczne (czy to wskażemy czy nie) – Wszystkie atrybuty są dodatkowo statyczne i final ● Nie ma problemu jak w klasie jest atrybut o tej samej nazwie ● Wygodniej się do nich odwoływać przez nazwę klasy, a nie referencję do obiektu ● trzeba je zainicjować w miejscu deklaracji – Nie mogą zawierać bloków inicjalizacji class Pracownik extends Osoba // dziedziczenie po klasie class Samochód implements Pojazd, Towar // dziedziczenie po kilku interfesjach class Chomik extends Ssak implements Puchate, DoGłaskania // dziedziczenie po klasie i kilku interfejsach Przygotował: Jacek Sroka 31 Przykład interfejsy interface IntA { public void metodaA(); public void metodaC(); } interface IntB { public void metodaB(); public void metodaC(); } class NadKl { public void metodaC() {...} } class PodKl extends NadKl implements IntA, IntB { public void metodaA() {...} public void metodaB() {...} //metodaC() jest w nadklasie } Przygotował: Jacek Sroka 32 Uogólnianie interfejsów Tu wielodziedziczenie jest pełne! interface IntA {...} interface IntB {...} interface IntC extends IntA, IntB { public void metodaD(); } class KlC implements IntC { public void metodaA() {} public void metodaB() {} public void metodaC() {} public void metodaD() {} } KlC cc = new KlC(); IntC ic = cc; IntA ia = cc; IntB ib = ic; Przygotował: Jacek Sroka 35 Modyfikatory przykład c.d. package mój.pakiet2; import jakies.klasy.*; public class Test { public static void main(String[] args) { inny.pakiet.Modyfikatory modyf; modyf = new inny.pakiet.Modyfikatory(); modyf.a = 1; //modyf.b = 2; //modyf.c = 3; //modyf.d = 4; } } ----------------------------------------------------------- package inny.pakiet; public class Modyfikatory { public int a; protected int b; int c; private int d; } Przygotował: Jacek Sroka 36 Modyfikatory c.d. ● Prawa dostępu dotyczą klas, a nie obiektów – programowanie aspektowe ● Atrybuty zazwyczaj deklarujemy jako prywatne lub chronione – Konwencja get, set, is ● Dostęp prywatny w całej klasie na najwyższym poziomie class Zewnętrzna { class Lokalna1 { private int i1; } class Lokalna2{ int met(){return new Lokalna1().i1;} } } ● Typ tablicowy jest dostępny tylko jak dostępny jest typ elementu ● Klasa lub interfejs z najwyższego poziomu mogą mieć jedynie dostęp publiczny lub domyślny pakietowy ● Przy dziedziczeniu nie można ograniczyć widoczności (bo podstawialność) Przygotował: Jacek Sroka 37 protected package test1; public class Parent { protected int x = 0; } -------------------- package test2; public class Child extends test1.Parent { public void test() { System.out.println("x="+x); //test1.Parent p = new test1.Parent(); //System.out.println("p.x="+p.x); } }