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 3 Kapsułkowanie przypomnienie/zagadka Czy w poniższym zawsze left == right/3 class Foo { public int left = 12; public int right = 4; public void setleft(int l) { left = l; right = l/3; // reszta skomplikowanego kodu
Przygotował: Jacek Sroka 4 Zasięg deklaracji lokalnych Pracownik prac1 = new Pracownik("Jacek", 10000f); //tylko prac1 { Pracownik prac2 = new Pracownik("Placek", 8000f); //prac1 i prac2 //zmiennych lokalnych nie wolno przesłaniać //źle: Pracownik prac1 = new Pracownik("Jacek", 10000d); //tylko prac1
Przygotował: Jacek Sroka 5 Zagadka public class ScopeTest { int x; void test1() { x = x + 2; int x = 1; x = x++; System.out.println(x); void test2(int x) { System.out.println(x); System.out.println(this.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 8 Dziedziczenie, Interfejsy, Pakiety Dziedziczenie to nowy dla OO sposób na ponowne wykorzystanie kodu nadklasy są zazwyczaj bardziej ogólne/abstrakcyjne nie widzą nic o swoich podklasach metody z nadklasy są automatycznie dostępne w podklasach, ale można je przesłonić (z dokładnością do modyfikatorów dostępu) Nadklasy abstrakcyjne mogą nie definiować wszystkich metod wtedy nie można tworzyć egzemplarzy Interfejsy nie definiują żadnych metod namiastka wielodziedziczenia Klasy są grupowane w pakiety przestrzenie nazw sposób dystrybucji
Przygotował: Jacek Sroka 9 Wielokrotne użycie kodu Agregacja całkowita (ang. composition) związek całość część Czas życia część ograniczony przez czas życia całości Część należy tylko do jednej całości Klasa tworzy i używa obiekty innych klas Okienko Ramka Uogólnienie (ang. generalization) związek między nadklasą i podklasą Podklasa jest szczególnym przypadkiem nadklasy Podklasy można używać wszędzie tam gdzie nadklasy Nie zależy od implementacji klas (to że w tej chwili są podobnie zaimplementowane nie ma znaczenia) Dziedziczenie i przedefiniowywanie metod Przykłady: Owoc-Gruszka, Ptak-Wrona, Figura-Kwadrat Okienko Dialog
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 13 instanceof Dynamiczne sprawdzanie typów jest niewygodne, bo błędy pojawiają się w trakcie uruchomienia, a nie kompilacji, ale można się trochę zabezpieczyć operator instanceof if (o instanceof Student) { Student s = (Student) o; s.idźnawykład(); //lub ((Student) o).idźnawykład(); Dla każdej referencji do obiektu spełnione jest??? instanceof Object null nie jest egzemplarzem żadnej klasy (null instanceof Object) == false Tablice też są obiektami (new int[5] instanceof Object) == true Przemieszanie hierarchii klas da się wykryć w czasie kompilacji class Cat { class Dog { Dog d = new Dog(); System.out.println(d instanceof Cat);
Przygotował: Jacek Sroka 14 Wzorce projektowe Pewne wypróbowane i poprawne rozwiązania problemów projektowych mogą być (i były) wyrażane jako dobre praktyki, heurystyki lub wzorce nazwane przepisy zadanie-rozwiązanie. (na podstawie "Applying UML And Patterns" Craiga Larmana). Sam termin wzorzec ma sugerować coś powtarzalnego. To nie są nowe pomysły! Dwa istotne zbiory wzorców to wzorce GoF i GRASP. GRASP to metodyczne podejście do uczenia się podstaw projektowania obiektowego. GRASP: Wysoka spójność, Luźne sprzężenie, Polimorfizm, Rzeczoznawca, Twórca, Zarządca, Pośrednictwo, Czysty wymysł, Kapsułkowanie zmienności GoF (23 ogólnie uznane wzorce): Fabryka, Singleton, Adapter, Strategia, Kompozyt, Fasada, Obserwator (Delegowanie, Wydawca-Prenumerator)
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 18
Przygotował: Jacek Sroka 19 Pakiety przykład package mój.pierwszy.pakiet; import java.util.date; public class MojeUtils { public static void main(string[] args) { System.out.println("Witaj Świecie!"); javac./mój/pierwszy/pakiet/mojeutils.java java mój.pierwszy.pakiet.mojeutils
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 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 23 Import składowych statycznych Przykład dla stałych (można też metody) double r = Math.cos(Math.PI * theta); import static java.lang.math.pi; import static java.lang.math.*;//też mogą wystąpić konflikty nazw //np. MAX_VALUE z Integer i Long double r = cos(pi * theta); Przydaje się z java.util.arrays i java.util.collections Stosować oszczędnie żeby nie zaśmiecić przestrzeni nazw jeszcze gorzej Constant Interface Antipattern, bo zaśmieca publiczne API
Przygotował: Jacek Sroka 24 Niektóre standardowe pakiety java.lang (Object, String, Integer,..., System, Math, Throwable, Thread) java.io (File, Reader, Writer, InputStream, OutputStream) java.net (Socket, ServerSocket, URL) java.util (Collection, List, Set, Map, Iterator) javax.swing...
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 28 Klasy abstrakcyjne przykład abstract class Pojemnik { public abstract void dodaj(int elt); public void dodajtab(int[] tab){ for(int i: tab) dodaj(i); public abstract String tostring(); //mimo że tostring() było zdefiniowane w Object
Przygotował: Jacek Sroka 29 public class PojemnikTablicowy extends Pojemnik { private int[] tab; // Niezm.: dane są w tab[0..ile-1] private int ile=0; PojemnikTablicowy(){ tab = new int[1]; // 1024 byłoby bardziej naturalne @Override public void dodaj(int elt){ if (ile >= tab.length){ int[] pom = new int[tab.length*2]; for (int i=0; i<ile; i++) pom[i] = tab[i]; // System.arraycopy(tab, 0, pom, 0, ile); tab = pom; // nie ma to jak automatyczne odśmiecanie :) // teraz już na pewno jest miejsce tab[ile++] = elt; @Override public String tostring(){ String wyn="["; // Powinien być StringBuilder for (int i=0; i<ile-1; i++) wyn += tab[i] + ", "; if (ile>0) wyn+=tab[ile-1]; wyn+="]"; return wyn; // tostring // PojemnikTablicowy
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 33 Inne modyfikatory abstract (klasa, metoda) nie można tworzyć egzemplarzy (ale można odpalić main) final (klasa, metoda, zmienna) blokujemy rozszerzanie; stałe z raz przypisaną wartością (dotyczy referencji, nie stanu obiektu); użyte w wielu klasach podstawowych, np. String native (metoda) odwoływanie się do zależnej od platformy implementacji w innym języku, jak np. C static (metoda, atrybut) składowe klasy; stałe synchronized (metoda) sekcja krytyczna volatile (zmienna) wszystkie wątki dotykające tej zmiennej muszą uzgodnić swoją prywatną kopię zmiennej z główną kopią w pamięci transient (atrybut) nie serializować strictfp (klasa, metoda) obliczenia zmiennopozycyjne niezależnie od platformy, według IEEE 754 (może ograniczyć precyzję) abstract i final oraz abstract i private oraz abstract i static się wykluczają abstract, final i static nie dotyczą konstruktorów
Przygotował: Jacek Sroka 34 Modyfikatory przykład package mój.pakiet1; import jakies.klasy.*; //kolejność definicji klas jest nieistotna public class Test { public static void main(string[] args) { Modyfikatory modyf = new Modyfikatory(); modyf.a = 1; modyf.b = 2; modyf.c = 3; //modyf.d = 4; //klasy mogą mieć jedynie dostęp pakietowy lub public class Modyfikatory { public int a; protected int b; int c; private int d;
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);
Przygotował: Jacek Sroka 38 Typy wyliczeniowe Od Javy 5.0 Przykład poza klasą enum Ocena { BDB, DB, DST, NDST ; Ocena o = Ocena.BDB; Przykład w klasie class Egzamin { enum Ocena { BDB, DB, DST, NDST ; Ocena o; Egzamin egz = egz.o = Egzamin.Ocena.BDB; średniki na końcu są zazwyczaj opcjonalne mogą zawierać konstruktory, metody i zmienne
Przygotował: Jacek Sroka 39 Narzędzia java, javac, javadoc, javap Ant, Maven JUnit
Przygotował: Jacek Sroka 40 JUnit i testy jednostkowe