public abstract
Transkrypt
public abstract
Programowanie sieciowe Wykład 2: Java, cd. mgr inŜ. Paweł Kośla mgr Marcin Raniszewski Łódź, 2009 Plan wykładu Dziedziczenie Rzutowanie Pakiety Modyfikatory dostępu Metody i klasy abstrakcyjne Interfejsy UŜyteczne klasy Wyjątki Aplikacja graficzna Modelowanie okna Obsługa zdarzeń 2 Dziedziczenie UmoŜliwia tworzenie z danej klasy klas pochodnych (podklas). Klasa pochodna dziedziczy pola i metody po klasie bazowej (nadklasie). MoŜna z nich korzystać tak, jakby były zadeklarowane w danej klasie. (ograniczenia poprzez modyfikator dostępu private) Podklasa moŜe dziedziczyć tylko po jednej nadklasie. Klasa pochodna moŜe mieć swoje klasy pochodne – w ten sposób powstaje hierarchia klas. KaŜda klasa dziedziczy po klasie Object – klasie bazowej wszystkich klas w Javie 3 Dziedziczenie public class KlasaBazowa { public int i; public void wypisz() { System.out.println(„Wartosc i: ” + i); } } public class Pochodna public void metoda() } extends KlasaBazowa { { } … Pochodna obiekt = new Pochodna (); obiekt.i = 3; obiekt.metoda(); obiekt.wypisz(); // Wartosc i: 3 4 Dziedziczenie Przysłanianie metod pozwala na powtórne deklarowanie w klasie pochodnej tych samych metod co w klasie bazowej. Nie moŜna przysłaniać metod z modyfikatorem final. Nie moŜna zmieniać typu metody statycznej na niestatyczną class Pochodna extends KlasaBazowa { void wypisz() { System.out.println(“Metoda wywolana w podklasie”); } } … obiekt.wypisz(); // Metoda wywolana w podklasie 5 Słowa super i this Słowo kluczowe super uŜywane jest przy odwołaniach do metod, konstruktorów i pól przodka (nadklasy) Słowo kluczowe this oznacza obecny obiekt klasy public class Wzor { public int zmienna; Wzór(int i) { zmienna = i; } } public class Klasa extends Wzor { int a, b = 10; Klasa() { super(7); } public void setA(int a) { this.a = a; } } 6 Rzutowanie Java w razie potrzeby zamieni automatycznie jeden typ danych na inny (przypisanie wartości int do double). Rzutowanie umoŜliwia wskazanie konwersji lub wymuszenie konwersji w miejscu, w którym normalnie by nie nastąpiła. void rzutowanie() { int i = 300; long l = (long)i; long l2 = (long)300; } MoŜna rzutować zmienną jak i wartość liczbową. PowyŜsze rzutowanie jest zbyteczne, gdyŜ jest zapewnione automatycznie (typ mniejszy rzutujemy na większy). Java pozwala na rzutowanie kaŜdego typu podstawowego na kaŜdy inny typ podstawowy, oprócz typu logicznego, który w ogóle nie moŜe być rzutowany. 7 Rzutowanie long l = 223372036854775L; int i = (int)l; System.out.println(i); PowyŜszy kod wypisze na standardowe wyjście iterał -622275593. Jeśli nie wpisalibyśmy jawnej konwersji, kompilator zgłosiłby błąd: Type mismatch: cannot convert from long to int. Aby rzutować klasy, potrzebne są specjalne metody, które taką konwersję wykonają (wyjątek stanowi klasa String: klasa Object zawiera metodę toString(), która umoŜliwia konwersję dowolnej klasy na obiekt typu String). MoŜliwe jest rzutowanie w ramach rodziny typów, czyli typów dziedziczących (moŜna rzutować String na Object (rzutowanie w górę) i Object na String, o ile obiekt jest rzeczywiście typu String (inaczej otrzymamy wyjątek ClassCastException)). 8 Pakiet Pakiety są bibliotekami klas. Klasy kompilowane z deklaracją pakietu package naleŜą do pakietu o nazwie podanej w deklaracji. package dom; Nazwy pakietów tworzone są w sposób odpowiadający hierarchii ścieŜek, w której znajdują się klasy. package dom.kuchnia; class kuchenka {} Klasy kompilowane bez nazwy pakietu naleŜą do pakietu domyślnego . Instrukcja package musi być pierwszym elementem programu nie będącym komentarzem. Pakiety pełnią rolę porządkującą względem przestrzeni nazw i chronią przed kolizjami klas. Aby utrzymać porządek Java umieszcza wszystkie plik .class z danego pakietu w jednym katalogu. Zebranie plików pakietu w jednym podkatalogu ułatwia: - tworzenie unikatowych nazw pakietów, - odnajdywanie klas ukrytych w strukturze katalogów. ŚcieŜka dostępu ukryta jest w nazwie pakietu. Pliki z pakietu mojpakiet.graf zostaną umieszczone w katalogu mojpakiet/graf . 9 Pakiet Odwołując się do klas, które znajdują się w innych pakietach trzeba podać ich lokalizację: java.util.Date data = new java.util.Date(); PoniewaŜ jest to niewygodne, Java umoŜliwia importowanie pojedynczych klas lub całych pakietów. Aby włączyć pakiet do programu piszemy: import java.util.*; Import pojedynczej klasy: import java.util.ArrayList; Polecenie import jest odpowiednikiem instrukcji #include z języka C/C++. Kompilator nie zgłosi Ŝadnych zastrzeŜeń, nawet jeśli pakiet zostanie zaimportowany więcej niŜ jeden raz. 10 Modyfikatory dostępu Przy programowaniu obiektowym istotnym zagadnieniem jest „oddzielenie rzeczy, które się zmieniają od rzeczy, które pozostają takie same”. Postępowanie takie nazywa się hermetyzacją. Język Java dostarcza modyfikatory dostępu, które są uŜyteczne temu zagadnieniu. Dostępne poziomy dostępu to: • public, • protected, • “przyjazny”, pakietowy(ang. package) (bez określonego słowa kluczowego), • private. Modyfikatory dostępu umieszcza się przed definicją składnika klasy. Modyfikator naleŜy ustawić przed kaŜdym składnikiem klasy osobno. Nie obowiązuje tu zapis znany z C++. public class Klasa { public int i; private long l; double d; } 11 Modyfikatory dostępu Modyfikator private „przyjazny” protected public klasa + + + + pakiet podklasa wszędzie + + + + + Klasy nie mogą być ani typu private, ani typu protected (wyjątkiem klasy wewnętrzne). Aby uniemoŜliwić dostęp do danej klasy, naleŜy jej wszystkie konstruktory oraz pola statyczne uczynić prywatnymi (lub zaleŜnie od potrzeby określić dostęp na “przyjazny” lub chroniony). 12 Metody i klasy abstrakcyjne Metoda abstrakcyjna jest metodą niekompletną – zawiera tylko deklarację, nie posiada natomiast ciała. Deklaracja tej metody poprzedzona jest słowem kluczowym abstract. Jeśli klasa posiada co najmniej jedną metodę abstrakcyjną, wówczas staje się klasą abstrakcyjną i jej deklaracja musi być poprzedzona słowem kluczowym abstract. Przykład: abstract class Baza { void metoda() { return; } abstract public void metodaAbstract(); //brak ciała metody } 13 Metody i klasy abstrakcyjne Klasę abstrakcyjną tworzy się, gdy chcemy manipulować zestawem klas pochodnych poprzez wspólny interfejs. Mają one wyraŜać tylko interfejs, a nie określoną implementację. Jeśli dziedziczymy po klasie abstrakcyjnej i chcemy tworzyć obiekty klasy potomnej, wtedy musimy dostarczyć definicje wszystkich metod abstrakcyjnych klasy bazowej Przykład: abstract class Baza { void metoda() { return; } public abstract void metodaAbstract(); } class Jeden extends Baza { public void metodaAbstract() { //wszystkie klasy pochodne musza //mieć taka metodę zdefiniowaną System.out.println(„wyswietl tekst”); } } 14 Metody i klasy abstrakcyjne Jeśli nie zdefiniujemy wszystkich metod abstrakcyjnych w klasie pochodnej, nowa klasa stanie się klasą abstrakcyjną i kompilator zmusi nas do uŜycia słowa abstract takŜe w stosunku do niej. Przykład: abstract class Baza { void metoda() { return; } public abstract void metodaAbstract(); } abstract class Dwa extends Baza { void metoda(){ System.out.println(„w klasie Dwa”); } } 15 Metody i klasy abstrakcyjne Nie moŜna utworzyć obiektu dla klasy abstrakcyjnej. MoŜliwe jest zadeklarowanie klasy jako abstrakcyjnej mimo, Ŝe nie posiada Ŝadnych metod abstrakcyjnych. Przydatne jest to, gdy chcemy zapobiec tworzenia obiektów naszej klasy, mimo Ŝe nie ma sensu deklarowania którejkolwiek z metod jako abstrakcyjną. 16 Interfejs Słowo kluczowe interface produkuje klasę całkowicie abstrakcyjną. Klasa ta nie zawiera Ŝadnej implementacji, a jedynie zbiór metod które musi zawierać implementująca go klasa. Interfejsy zawierają tylko publiczne metody abstrakcyjne (niejawne public abstract) oraz tylko statyczne, finalne i publiczne pola (niejawnie public static final) Dzięki interfejsom moŜemy w języku Java wprowadzić mechanizm znany z języka C++ „wielokrotnego dziedziczenia”. Interfejsy pozwalają ustanowić formę klasy: nazwy metod, listy argumentów oraz typy zwracane – jednak bez ciał metod. Interfejs mówi nam: „oto jak będą wyglądać wszystkie klasy implementujące mnie”. Przykład: interface Instrument { int i = 5; //automatycznie public static i final String what(); //automatycznie public abstract void play(int num); //automatycznie public abstract } 17 Interfejs Aby klasa mogła realizować dany interfejs naleŜy uŜyć słowa kluczowego implements. MoŜna implementować kilka interfejsów na raz („wielokrotne dziedziczenie”). MoŜna jednocześnie dziedziczyć (tylko po jednej klasie) i implementować (po wielu interfejsach) Przykład: class Gitara implements Instrument, Strunowy { String what() { return „Jestem Gitara”; } void play(int num) { System.out.println(„Gram dźwięk ”+num); } void strojenie() { System.out.println(„Wykonuje strojenie”); } } class Altowka extends Skrzypce implements Instrument, Strunowy { ... } 18 Interfejs Kiedy zatem stosować klasy abstrakcyjne, a kiedy interfejsy? JeŜeli chcemy stworzyć klasę bazową bez implementowania metod naleŜy wybrać interfejs. Jedynie w razie konieczności zdefiniowania metod warto posłuŜyć się klasą abstrakcyjną. 19 Sprzątanie (Garbage Collector) W Javie nie ma destruktorów. Zakończenie Ŝycia niepotrzebnych obiektów oraz odzyskanie pamięci czyli odśmiecanie (ang. Garbage Collecting) następuje asynchronicznie i jest wykonywane przez specjalny wątek o niskim priorytecie. Odśmiecanie moŜna wymusić wywołując metodę: System.gc() 20 UŜyteczne klasy biblioteczne Standardowe pakiety: java.applet - tworzenie apletów java.awt – okienka AWT java.beans – uniwersalne komponenty java.io – operacje wejścia/wyjścia java.lang – podstawowe klasy java.math – wielkie liczby java.net – współpraca z siecią java.rmi – przetwarzanie rozproszone java.security – bezpieczeństwo java.sql – zapytania do baz danych java.text – operacje na tekście java.util – klasy pomocnicze javax.swing – okienka Swing 21 UŜyteczne klasy biblioteczne Klasa Object Klasa Object jest nadklasą dla wszystkich obiektów. Zapis class Klasa{..} jest więc równoznaczny z zapisem class Klasa extends Object {…}. Klasa Object zawiera kilka uŜytecznych metod: clone() – tworzy bliźniaczy obiekt. equals(Object) – porównuje obiekty. finalize() – umieszczamy w niej instrukcje zwalniające zasoby uŜywane przez klasę, metoda jest wywoływana przez Garbage Collector przed zwolnieniem obiektu z pamięci. toString() – przedstawia reprezentację obiektu w postaci łańcucha znaków. 22 UŜyteczne klasy biblioteczne Klasa String Klasa String reprezentuje łańcuch znaków. KaŜda sekwencja znaków zamknięta cudzysłowami jest interpretowana jako obiekt tej klasy. WaŜniejsze metody: length() – zwraca długość łańcucha. charAt(int i) – zwraca znak z łańcucha z podanego miejsca. equals(String str), equalsIgnoreCase(String str), compareTo(String str) – porównuje znaki dwóch ciągów. substring(…) – grupa metod zwracających podłańcuch. concat(String) lub operator + - zwraca złączenie dwóch łańcuchów. toLowerCase(), toUpperCase() - konwersja na małe, wielkie litery. replace(znak1, znak2) – zastępowanie znaków w łańcuchu. 23 UŜyteczne klasy biblioteczne Klasa Math potęgowanie i pierwiastkowanie – pow(a,b), sqrt() funkcje trygonometryczne – cos(), sin(), tan() logarytm naturalny – log(a) zaokrąglanie w górę/dól – ceil(a), floor(a) zaokrąglanie do liczby całkowitej – round(a), rint(a) wartość bezwzględna – abs(a) Stałe - PI i E Niektóre funkcje mogą zwrócić specjalne wartości dla liczb zmiennoprzecinkowych: nie liczba: NaN nieskończoność: POSITIVE_INFINITY, NEGATIVE_INFINITY 24 UŜyteczne klasy biblioteczne Typy danych odnośnikowych W pakiecie java.lang.* znajdują się następujące klasy typów danych: Boolean, Byte, Short, Integer, Long, Float, Double Character Dają one moŜliwość przechowywania pola o wartości odpowiadającego typu podstawowego UmoŜliwiają konwersję na inne typy danych np. intValue() - konwersja do int floatValue() - konwersja do typu float longValue() - konwersja do typu long parseInt() - w klasie Integer, parsowanie obiektu String do typu int parseDouble() - w klasie Double, parsowanie String do double 25 Sprawdzanie równości obiektów Działanie operatorów == i != w stosunku do obiektów moŜe być zaskakujące: public class Rownosc { public static void main(String[] args){ Integer n1 = new Integer(47); Integer n2 = new Integer(47); System.out.println(n1 == n2); } } Wykonanie klasy Rownosc da wynik: false Dlaczego? MoŜe się wydawać, Ŝe obiekty n1 i n2 są takie same. Ale n1 i n2 to nie obiekty, tylko referencje do obiektów (dwie, róŜne). Aby porównać zawartość obiektów, naleŜy uŜyć specjalnej metody equals() zdefiniowanej dla wszystkich obiektów (ale nie dla typów podstawowych, dla których dobrze działają == i !=): public class Rownosc { public static void main(String[] args) { Integer n1 = new Integer(47); Integer n2 = new Integer(47); System.out.println(n1.equals(n2)); } } 26 Wyjątki Wyjątek to zdarzenie, które moŜe się pojawić podczas wykonywania programu, powodujące przerwanie normalnego przepływu sterowania (wykonywania kolejnych instrukcji). Wyjątki pojawiają się kiedy nastąpiła jakaś nieprawidłowa sytuacja (np. dzielenie przez 0), która moŜe wymagać dodatkowego obsłuŜenia. Hierarchia klas wyjątków: 27 Wyjątki Zalety wyjątków: oddzielenie kodu obsługującego błędy, propagowanie błędu przez kolejne metody, moŜliwość grupowania błędów. 28 Wyrzucanie wyjątków UŜytkownik moŜe wyrzucać wyjątki za pomocą słowa kluczowego throw if(str.equals(“koniec”)) { throw new Exception(“Zglaszam wyjatek”); } Jeśli wyjątek nie jest obsłuŜony wewnątrz metody wymagana jest deklaracja jego wyrzucenia przez tę metodę. SłuŜy do tego słowo kluczowe throws: int read() throws java.io.IOException { ... } 29 Przechwytywanie wyjątków Wyjątek moŜna wyrzucić dalej (słowo kluczowe throw) lub przechwycić za pomocą instrukcji try-catch int metoda(String str) throws Exception { try { Integer.parseInt(str); } catch(NumberFormatException e){ throw new Exception(); // lub obsłuŜyć. } } Po jednym bloku try, moŜe znajdować się kilka bloków catch. Bardzo uŜyteczną metodą w przypadku wyjątków jest metoda: public void printStackTrace(), która wypisuje na standardowe wyjście stos zgłoszeń wyjątków przez kolejne metody aŜ do miejsca, w którym jest wywołana. Jest to niezmiernie pomocne przy wyszukiwaniu powodu błędów w rozbudowanych aplikacjach, kiedy wyjątki są przekazywane przez dziesiątki metod. 30 Przechwytywanie wyjątków WaŜna jest kolejność bloków catch, gdyŜ wyjątek zostanie obsłuŜony przez pierwszy dobrze pasujący blok catch. Zaczynamy od obsługi wyjątków szczegółowych a następnie przechodzimy do typów ogólniejszych. try{ Integer.parseInt(str); } catch(NumberFormatException e){ } catch(RuntimeException e){ } java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.NumberFormatException try{ Integer.parseInt(str); } catch(RuntimeException e){ } catch(NumberFormatException e){ } 31 Przechwytywanie wyjątków finally Często mamy taki fragment kodu, który chcielibyśmy wykonać niezaleŜnie od tego czy w bloku try został zgłoszony wyjątek czy teŜ nie (np. zamknięcie operacji na pliku). Aby to osiągnąć, na końcu procedur wyjątków umieszcza się sekcję finally: try{ //Obszar który moŜe wyrzucić wyjątki A, B, C } catch (A a){ // Obsluga dla wyjatku A } catch (B b){ // Obsluga dla wyjatku B } catch (C c){ //Obsluga dla wyjatku C } finally{ //Czynnosci, ktore sa wykonywane za kazdym razem } 32 GUI Java dostarcza dwa graficzne interfejsy uŜytkownika, będące częścią Java Foundation Classes: Abstract Window Toolkit (AWT) , Swing. Pakiety AWT i Swing zawierają dwie podstawowe klasy: Component – zawierającą metody dostępu do komponentów graficznych oraz metody pozwalające na zmianę ich właściwości, Container – podklasa Component, dostarczająca tzw. pojemników, czyli obiektów grupujących komponenty. Istnieją dwa podstawowe pojemniki (klasy): Window – definiujący okno, które będzie wyświetlane np. jako część aplikacji, Panel – musi być częścią innego pojemnika, np. apletu lub okna. 33 GUI Podklasami Window są klasy Dialog i Frame. Klasa Frame pozwala na zdefiniowanie głównego okna, określenie jego tytułu, a takŜe zmianę jego wyglądu oraz rozmiaru. Klasa Dialog jest klasą która tworzy okno dialogowe i musi mieć swojego właściciela. Komponenty (takŜe inne pojemniki) do pojemników nadrzędnych przypisujemy metodą add(); . Przykład: import java.awt.*; … public static void main(String args[]){ Frame f = new Frame(“Tytuł okna”); f.setSize(200,100); Button b = new Button(“OK”); f.add(b); f.setVisible(true); } 34 Zarządzanie układem Do rozmieszczenia komponentów w pojemnikach wykorzystuje się klasy zarządzające układem (ang. Layout Manager). BorderLayout – domyślny układ dla pojemnika Frame; powoduje ułoŜenie elementów poprzez przyciągnięcie ich do następujących rejonów: NORTH, SOUTH, WEST, EAST, CENTER(domyślne) Button b2 = new Button(„OK2”); f.add(b, BorderLayout.SOUTH); 35 Zarządzanie układem FlowLayout jest domyślnym układem dla pojemnika Panel. Komponenty dodawane są od lewej do prawej i mają rozmiary domyślne (nie są powiększane na cały pojemnik) public static void main(String args[]){ Frame f = new Frame(“Tytuł okna”); f.setSize(200,100); f.setLayout(new FlowLayout()); //zmieniamy układ Button b = new Button(“OK”); f.add(b); Button b2 = new Button(“OK2”); f.add(b2); f.setVisible(true); } 36 Panele public static void main(String args[]){ Frame f = new Frame(“Tytuł okna”); f.setSize(200,100); Panel p = new Panel(); Button b = new Button(“OK”); p.add(b); //dodanie do panela f.add(p, BorderLayout.NORTH); Button b2 = new Button(“OK2”); f.add(b2, BorderLayout.SOUTH); f.setVisible(true); } 37 Komponenty tekstowe w AWT AWT dostarcza następujące komponenty tekstowe: etykieta: Label pole edycji: TextField duŜe pole edycji: TextArea Frame f = new Frame(“Tytuł okna”); Panel p = new Panel(); Label lbl = new Label(„Etykieta”); p.add(lbl); TextField tf = new TextField(„Pole edycji”); p.add(tf); TextArea ta = new TextArea(„”,10,30); p.add(ta); f.add(p); f.setVisible(true); 38 Komponenty wyboru w AWT AWT dostarcza następujące komponenty wyboru: przyciski wyboru: Checkbox lista rozwijana: Choice lista wyboru: List Checkbox check = new Checkbox("checkbox"); panel.add(check); Choice ch = new Choice(); ch.add("pierwszy"); ch.add("drugi"); ch.add("trzeci"); panel.add(ch); List lst = new List(4); lst.add("pierwszy"); lst.add("drugi"); lst.add("trzeci"); panel.add(lst); 39 Pakiet Swing Swing to graficzny interfejs uŜytkownika Java drugiej generacji. Został opracowany w trakcie istnienia Javy 1.1 i włączony do JDK 1.2 jako podstawowy interfejs graficzny. Swing nie uŜywa narzędzi systemowych do tworzenia elementów interfejsu, oparty jest na wewnętrznych klasach Javy, co zapewnia pełną niezaleŜność od platformy (lekkie komponenty). Hierarchia klas Swing jest prawie identyczna z hierarchią klas AWT. Nazewnictwo klas: JComponent, JButton, JFrame . 40 Pakiet Swing Okna dialogowe słuŜące do komunikacji z uŜytkownikiem. Klasa JOptionPane showMessageDialog(...) showConfirmDialog(...) JOptionPane.YES_OPTION JOptionPane.NO_OPTION JOptionPane.CANCEL_OPTION Klasa JFileChooser 41 Obsługa zdarzeń Komponenty i inne obiekty GUI komunikują się ze sobą poprzez wysyłanie i odbieranie zdarzeń. Zdarzenia (pochodne EventObject) wysyłane są przez dany obiekt do jednego lub kilku innych obiektów, tzw. multicast. Obiekty odbierają zdarzenia poprzez metody je obsługujące (tzw. event handlers). Odbiorcy zdarzeń (klasy implementujące EventListener) deklarują jakimi zdarzeniami są zainteresowane. Button1 słuchacz1 słuchacz2 Button2 słuchacz3 Text 42 NajwaŜniejsze zdarzenia w GUI W Javie istnieje wiele zdarzeń oraz interfejsów je obsługujących (na róŜnych poziomach w hierarchii klas). Z punktu widzenia GUI najwaŜniejsze zdarzenia to: - zdarzenia wysyłane przez komponenty: ActionEvent - zdarzenia wysyłane przez myszkę: MouseEvent - zdarzenia wysyłane przez klawiaturę: KeyEvent - zdarzenia wysyłane przez okno: WindowEvent Odpowiadają im następujące interfejsy, odbierające zdarzenia: - ActionListener - MouseListener i MouseMotionListener - WindowListener (WindowAdapter) 43 Window Listener Przykład zamykania aplikacji: import java.awt.*; import java.awt.event.*; public class Start { public static void main(String args[]) { Frame f = new Frame("tytul okna"); SluchaczOkna lst = new SluchaczOkna (); f.addWindowListener(lst); f.setVisible(true); } } class SluchaczOkna extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } 44 Action Listener Przykład obsługi przycisku: import java.awt.event.*; import java.awt.*; public class Start{ public Start() { Frame frame = new Frame(); frame.setSize(500, 400); Button btn = new Button("Klik"); btn.addActionListener(new Sluchacz()); frame.add(btn); frame.setVisible(true); } //inaczej: //Sluchacz sl = new Sluchacz(); //btn.addActionListener(sl); public static void main(String[] args) { Start str = new Start(); } class Sluchacz implements ActionListener { public void actionPerformed(ActionEvent e){ System.out.println("Wcisnales przycisk"); } } } 45