Pobierz Zaawansowane programowanie obiektowe i więcej Notatki w PDF z Programowanie obiektowe tylko na Docsity! Zaawansowane programowanie obiektowe Wykład 1 JAVA Język java Rok 1990, Bill Joy: „utworzenie obiektowego środowiska w oparciu o C++” Język OAK (Object Application Kernel), 1991 Projekt Green, James Gosling, Patrick Naughton, Mike Sheridan
Przetwatzanie progtamów użytkownika
Edytor
MyProgram.java
Interpretator
Kompilator
PC - Windows 95/NT
< MyProgram.class
Interpretator
SUN - Solaris
Cechy języka Java automatyczne odśmiecanie (garbage collection) nie dopuszcza arytmetyki wskaźnikowej ścisła kontrola typów (konwersje) obsługa wyjątków wbudowane elementy współbieŜności Przykład Programem w języku Java jest aplikacja (application) lub aplet (applet). Aplikacja jest programem samodzielnym, zaś aplet jest programem wbudowanym (np. w przeglądarkę WWW). KaŜda aplikacja musi zawierać dokładnie jeden moduł źródłowy nazywany modułem głównym aplikacji, którego klasa zawiera publiczną funkcję klasy Jak działa interpretator? wyszuka plik o nazwie Hello.class, czy klasa Hello zawiera publiczną metodę statyczną main wykona instrukcje zawarte w bloku main. W języku Java kaŜda instrukcja kończy się średnikiem, który pełni rolę symbolu terminalnego. Jak działa interpretator? do metody main jako parametr jest przekazywana (z wiersza rozkazowego) tablica obiektów (łańcuchów) klasy String; metoda main nie zwraca wyniku (typem zwracanym jest void); Ciało main zawiera jedną instrukcję; System.out.print("Hello, World!\n"); Jak działa interpretator? Słowo System jest nazwą klasy w standardowym środowisku języka. Klasa System zawiera statyczny obiekt składowy typu PrintStream o nazwie out wywołanie System.out oznacza pisanie do standardowego strumienia wyjściowego. package moje.aplikacje; import javax.swing.*; import java.awt.Container; class PierwszyGUI extends JFrame { public PierwszyGUI () { ... } } class KlasaStartowa { PierwszyGUI ob1; PierwszyGUI ob2 = new PierwszyGUI (); public static void main (String[] args) { ... } } Określenie nazwy pakietu, do którego naleŜą klasy zdefiniowane w tym pliku. MoŜna opuścić. Zewnętrzne pakiety (ew. pojedyncze klasy lub interfejsy), z których korzystamy w naszym programie. MoŜna uwaŜać ten element jako odpowiednik dyrektywy #include w C/C++. Definicje klas (klasy mogą dziedziczyć, jak w tym przykładzie). Metoda main klasy startowej. To od niej rozpoczyna się wykonywanie aplikacji. Musi być to metoda public static ! Inna klasa. Posiada składniki, które mogą być inicjalizowane. Definicja konstruktora. Aplikacja graficzna import javax.swing.*; class GUI extends JFrame { public static void main (String[] args) { GUI gui = new GUI (); gui.setSize (300, 200); gui.show (); } } Klasa z metodą main dziedzicząca z klasy JFrame (opisującej okienko graficzne), która pochodzi z pakietu javax.swing. Korzysta z najprostszych odziedziczonych metod. Struktura programu package ... // deklaracja pakietu (niekonieczna) import ... // deklaracje importu; zwykle, a1e nie zawsze potrzebne import ... /** Komentarz dokumentacyjny zaczyna się ukośnikiem z dwoma gwiazdkami, kończy gwiazdką i ukośnikiem */ // To jest klasa A <- to jest komentarz public class A { . . . } /* To jest komentarz wielowierszowy */ // To jest klasa B class B { ...... } Klasy (przypomnienie) class nazwy klasy { Ciało klasy } Przed słowem kluczowym class moŜe wystąpić jeden ze specyfikatorów: abstract, public, final, lub dwa z nich: np. public abstract, public final. Abstract: klasa abstrakcyjna nie moŜe wystąpić; final: klasa nie moŜe mieć podklas; Brak specyfikatora: klasa dostępna tylko dla tego pakietu; Po nazwie klasy mogą wystąpić frazy: a) ‘extends nazwa_superklasy’ b) ‘implements nazwy_interfejsów’. a) klasa dziedziczy publicznie (zawsze) od klasy superklasa. b) w danej klasie zostaną zdefiniowane metody, zadeklarowane w implementowanych interfejsach. Przykład public class Point { int x, y; } równowaŜne public class Point { int x, y; public Point() { super(); } } przykład class Point {int x,y; Point() {x=1; y=2;}} class CPoint extends Point {public int color = 0xFF00FF;} public class Super1 { public static void main(String args[]){ CPoint cp=new CPoint(); System.out.println("cp.color="+cp.color); System.out.println("cp.x="+cp.x); }//end main }//end Super1
class Point ( int x,y; Point(int m, int y)
(this.x = x; this.y=y; | |
class CPoint extends Point I
static final int WHITE = 0, BLACK = 1;
int color;
CPoint(int x, int y) f this(x,y,WHITE); |
CPoint(int x, int y, int color) ( super(x,y); this.color=color; )
l
public class Super2 |
public static void main(String args[]) |
int a= 10, b= 20;
CPoint cp = new CPoint(a,b);
System.out.println("cp.color= " + cp.color);
System.out.println("cp.x= " + cp.x);
|//end main
ł//end Super?
Interfejsy interface Speakable { int QUIET = 0; int LOUD = 1; String getVoice(int voice); } interface Moveable { void startMoving(); void stopMoving(); } class Pies extends Zwierz implements Speakable, Moveable { Pies () {} Pies(String s) { super(s); } String getTyp(){ return "Pies"; } public String getVoice(int voice) { if (voice == LOUD) return "HAU... HAU... HAU... "; else return "hau... hau..."; } public void startMoving() { System.out.println("Pies " + name +"biegnie"); } public void stopMoving() { System.out.println("Pies " + name +"stanął"); } } Interfejsy Pies kuba = new Pies("Kuba"); kuba.startMoving(); System.out.println(kuba.getVoice(Speakable.LOUD)); kuba.stopMoving(); void Wyscig(Moveable[] objects) { for (int i =0; i < objects.length; i++) objects[i].startMoving(); } Wyscig( new Moveable[] { new Pies(), new Samochod(), new Kot(), new Rower() } ); Pakiety Przykład 2: Java.awt.Button b = new Java.awt.Button("0k"); Przykład 4: import java.awt.*; // importuje wszystkie nazwy klas pakietu java.awt class A { Frame f = new Frame("Tytuł");// teraz moŜemy uŜyć teŜ prostej nazwy klasy Button b = new Button("0k");// teraz moŜemy uŜyć teŜ prostej nazwy klasy } Pakiet java.lang nie wymaga importu (m.in. zawiera klasy String i System). Przykład 3: import java.awt.Button; // importuje nazwę klasy Java.awt.Button class A { java.awt.Frame f = new java.awt.Frame("Tytuł"); Button b = new Button("Ok"); } Przykład 1: package moj_pakiet; Słowo kluczowe this SYTUACJA 1 class Para { int a; int b; void add(int a, int b){ this.a + = a ; this.b + = b; } } p.add(p1).add(p2).add( p3); co jest inną formą zapisu: p.add(p1); p.add(p2); p.add(p3); SYTUACJA 2 Para add(Para p) { a = a + p.a; b = b + p. b; return this; } SYTUACJA 3: patrz wywołanie konstruktora z innego konstruktora Składowe statyczne Uwaga: Ze statycznych metod nie wolno odwoływać się do niestatycznych składowych klasy (obiekt moŜe nie istnieć). MoŜliwe są natomiast odwołania do innych statycznych składowych. Przykład: statyczne pole i metoda Para p1 = null,p2 = null; . . . . . . if (Para.count == 0) Para p1 = new Para(1,1); else while (Para.count < 10) { p2 = new Para(2,2); p1.add(p2); } System.out.println(p1.count); Para.showCount(); p1.showCount(); p2.showCount(); class Para{ static int count = 0; Para(int x, int y) { count++; a = x; b = y; } static void showCount() { System.out.println ("Liczba utworzonych par: "+count); } } Słowo kluczowe final Thinking in Java, Bruce Eckel Pole statyczne i finalne Zajmuje tylko jeden określony fragment pamięci i nie moŜe ulec zmianie static final int A=5; static final int a= rand.nextInt(20); Finalne obiekty Stała jest referencja a nie obiekt, do którego się odwołuje MoŜna zmienić zawartość obiektu, ale referencja nie moŜe pokazywać na inny obiekt class Value { int i = 1; } public class FinalData { //stale czasu kompilacji: final int i1 = 9; static final int VAL_TWO = 99; public static final int VAL_THREE = 39; // Typowa stała publiczna final int i4 = (int)(Math.random()*20); static final int i5 = (int)(Math.random()*20); Value v1 = new Value(); final Value v2 = new Value(); static final Value v3 = new Value(); final int[] a = { 1, 2, 3, 4, 5, 6 }; public void print(String id) { System.out.println( id + ": " + "i4 = " + i4 + ", i5 = " + i5); } class Poppet { private int i; Poppet (int ii) {i=ii;} } public class BlankFinal { final int i = 0; // Zainicjowana zmienna ostateczne final int j; // Pusta zmienna ostateczna final Poppet p; // Puste odwołanie ostateczna BlankFinal() { j = 1; // Inicjalizacja zmiennej ostatecznej p = new Poppet(); } BlankFinal(int x) { j = x; // Inicjalizacja zmiennej ostatecznej p = new Poppet(); } public static void main(String[] args) { BlankFinal bf = new BlankFinal(); } } ///:~ Finalne argumenty metody Wewnątrz metody nie moŜna zmieniać wartości; public class FinalArguments { void with(final Gizmo g) { //! g = new Gizmo(); // Niepoprawne -- g jest ostateczna } void without(Gizmo g) { g = new Gizmo(); // OK -- g nie jest ostateczna g.spin(); } Metody finalne Blokada metody, zabronienie klasom wydziedziczonym zmian (zapobieganie przesłonięciu) Wydajność wywołanie w miejscu inline ominięcie normalnej procedury włączenia kodu kopiowanie rzeczywistego kodu Decydujący rozmiar kodu metody decyzja po stronie kompilatora Javy Interface interfejsy Klasy abstrakcyjne – udostępniają interfejs, bez definicji Forma klasy: Nazwa metody Lista argumentów Typy zwracane Zawierają pola: static final (ale nie puste zmienne finalne) Metody : public Przykład – „wielokrotne dziedziczenie” w Javie interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly { public void swim() {} public void fly() {} } public class Adventure { static void t(CanFight x) { x.fight(); } static void u(CanSwim x) { x.swim(); } static void v(CanFly x) { x.fly(); } static void w(ActionCharacter x) { x.fight(); } public static void main(String[] args) { Hero h = new Hero(); t(h); // Traktuje h jako CanFight u(h); // Traktuje h jako CanSwim v(h); // Traktuje h jako CanFly w(h); // Traktuje h jako ActionCharacter }} ///:~ Typy danych Typy proste wartości logiczne: prawda lub fałsz true false1boolean znaki Unicodu-0...655562char -1.xE+308...1.xE3088double liczby rzeczywiste-3.xE+38...3.xE+384float -9223372036854775808 ...9223372036854775807 8long -2147483648...21474836474int -32768...327672short liczby całkowite-128...127lbyte Znaczenieprzedziały wartościLiczba bajtów Nazwa typu Deklaracje Deklaracje typów prostych deklaracja jest zarazem definicją - wydziela w pamięci miejsce na przechowanie zmiennej danego typu. Deklaracja zmiennej typu obiektowego jest faktycznie deklaracją (i definicją) referencji do obiektu, nie wydziela natomiast w pamięci miejsca na przechowanie samego obiektu. String s ; s = "ala ma kota"; int a = l; String s = "ala ma kota"; Operatory i wyraŜenia Nierówności!= Operatory równości -== 6, lewe Stwierdzenie typuinstanceof Operatory relacyjne< <= >= > 5, lewe Przesunięcie bitowe w prawo bez znaku >>> Przesunięcie bitowe w prawo>> Przesunięcie bitowe<< 4, lewe NazwaOperatorPriorytet, Wiązanie Operatory i wyraŜenia Operatory przypisania%= += &= |= <<=13, prawe Operator warunku?:12, prawe Logiczna alternatywa||11, Logiczna koniunkcja&&10, Bitowa alternatywa|9, Bitowe wyłączające ALBO^8. Bitowa koniunkcja&7, NazwaOperatorPriorytet, Wiązanie Operatory x = a > b; //x boolean!!! x = a > b && c<d; String s1; String s2 = "Napis"; s1 = s2 + " tralala"; s1 = s1 + s2; int k = 1; s1 = k + k + s2; // 2Napis s1 = s2 + k + k; // Napis11 s1 = s2 + (k+k); // Napis2 s1 = k + k; // błąd kompilacji (jeden z argumentów musi być typu String) Instrukcja break int i = 0; int j = 0; outerloop: // etykieta while (i < 100) { i++; while(true) { j++; . . . . . . if (i + j > 10) break outerloop; // przerwanie pętli oznaczonej etykietą outerloop, a nie bieŜącej } } Zasięg zmiennych Uwaga: W Javie instrukcje wyraŜeniowe i sterujące moŜna umieszczać wyłącznie w metodach klasy lub w bloku statycznym Zasięg identyfikatora - fragment programu, w którym moŜe być uŜywany. Zasięg składowych klasy – w kaŜdym miejscu klasy (miejsce deklaracji nieistotne) Zasięg identyfikatorów definiowanych wewnątrz metody jest lokalny. Zasięg parametrów metody jest lokalny W metodzie metoda1() moŜemy odwoływać się do zmiennej a, zmiennej b oraz metody metoda2(), a w metodzie metoda2() moŜemy odwoływać się do zmiennej a, zmiennej c i metody metoda1. class A { int a; void metoda1(){ int b; } void metoda2() { int c; } } Przesłanianie nazw zmiennych NIE W Javie nie wolno przesłaniać zmiennych lokalnych w blokach wewnętrznych: int a; { int a; // BŁĄD kompilacji } TAK W konstruktorach i metodach moŜemy przesłaniać identyfikatory pól klasy: class A { int a; void metoda(){ int a = 0; // przesłonięcie a = a + 10; // zmienna lokalna; this.a++; // pole klasy } Inicjalizacja pól Przy tworzeniu obiektu pola klasy mają zagwarantowaną inicjalizację na wartości ZERO (0, false - dla typu boolean, null - dla typów obiektowych, nie dotyczy to lokalnych zmiennych. PRZYKŁAD JAWNEJ INICJALIZACJI class Para { static String text = "Pary"; static int x = -1; int a = x+1; int b = x+1; Para() { a++; b++; } static String getText() { return text; } void show(){ System.out.println("( " + a + "," + b + ")"); } } Kolejność inicjalizacji pól REGUŁY DOTYCZĄCE KOLEJNOŚCI: •kaŜde odwołanie do klasy inicjalizuje najpierw pola statyczne •tworzenie obiektu (new) inicjalizuje pola niestatyczne, po czym wykonywany jest konstruktor •kolejność inicjalizacji pól - według ich kolejności w definicji klasy (w podziale na statyczne i niestatyczne, najpierw statyczne) NIE (błąd: forward reference) class Para { static int y = x + 1; int a = x+1; int b = x+1; static int x = - 1; } TAK class Para{ static String text = "Pary"; int a = x+1; int b = x+1; Para() { ... } Para(int x){ ... } Para(int x, int y) { ... } static int x = -1; } Typ tablicowy Deklaracja tablicy tworzy referencję. Taka deklaracja nie alokuje pamięci dla samej tablicy. int[] arr; // arr jest referencją MoŜna pisać teŜ int arr[]; // arr jest zmienną typu int[], który jest typem obiektowym Alokowanie pamięci. Rozmiar tablicy moŜe być ustalany dynamicznie podczas działania programu arr = new int[l0]; int[] tab = new int[n]; Tablice - przykłady Component[] tab=new Component[]{new Button("A"), new Button("B"), new Label("A"), new Label("B"),}; for(int i=0;i<tab.length;i++) tab[i].setBackground(Color.blue); Tablice róŜnych obiektów (takie tablice takŜe jako argument funkcji) void chgtab(byte[] t){ for( int i=0; i < t.length; i++) t[i]++; } byte[] b1 = {1, 2, 3 }; chgtab(b1); Tablice jako argumenty metod Tablice wielowymiarowe Przykładowe sposoby deklaracji i inicjalizacji: 1. inicjalizacja w nawiasach klamrowych int[][] macierz2 = new int[n][m]; int[][] macierz1 = {{ l, 2, 3 }, { 4, 5, 6}}; 2. dynamicznie Tablice wielowymiarowe Przykładowe sposoby deklaracji i inicjalizacji: 3. tablica składa się z wektorów o róŜnych rozmiarach public static void main(String[] arg) { int w[] = { 2, 3, 4 }; int n = 3; int[][] m3 = new int[n][]; // rozmiary wierszy będą zm. Dynam. for(int i = 0; i < m3.length; i++){ m3[i] = new int[w[1]]; for (int j = 0; j < m3[i].length; j++) m3[i][j] = i + j; } for (int i = 0; i < m3.length; i++) { System.out.println("Rozmiar i-go wiersza " + m3[i].length); String out = " "; for(int j = 0; j < m3[i].length; j++) out += " " + m3[i][j]; System.out.println(out); } } 80 Tablice public static void main(String[] arg) { int[] w = { 2, 3, 4 }; int n = 3; int[][] m3 = new int[n][]; // row sizes - dynamic for(int i = 0; i < m3.length; i++){ m3[i] = new int[w[i]]; for (int j = 0; j < m3[i].length; j++) m3[i][j] = i + j; } for (int i = 0; i < m3.length; i++) { System.out.println("i-th row size: " + m3[i].length); String out = " "; for(int j = 0; j < m3[i].length; j++) out += " " + m3[i][j]; System.out.println(out); } } 81 double b = 1 / 3; // ? jak w C/C++: dzielenie całkowite, wynik: 0. zastosuj 1.0 / 3.0. Konwersja danych A co teraz? int c = 1.0 / 3.0;//error Java musi być pewna, Ŝe chcesz stracić pewną część informacji int c = (int)(1.0 / 3.0);//OK 82 Typy konwersji (arithmetic) int i; short sh; sh = 5; // OK; 5 is int but is constant and // is small enough (no information loss) i = sh; // expanding, ok sh = (short)i; // OK – with the explicit cast int2int double d = 5.12; i = d; // WRONG! Conversion must be explicit // but: i = (int)d; // OK. The fraction is cut off float2int 85 Powiązanie łańcuchów znaków i liczb String s1 = "Johnny has drunk "; int count1 = 2, count2 = 1; String s2 = " beers."; String s3 = s1 + count1 + s2; String s4 = s1 + (count1 + count2) + s2; String s5 = s1 + count1 + count2 + s2; String s6 = count1 + count2 + s2; 86 Przeładowanie metod • int Fun(int x) • int Fun(float y) • int Fun(int a, float b) Wszystkie w jednej klasie Error!! • int Fun(int x) and • boolean Fun(int y) PrzeciąŜanie metod p.add(jakasPara) ; p.add(3); p.add(1,2); void add(Para p) { a += p.a; b += p.b;} void add(int i) { a += i; b += i; } void add(int i, int k){a += i; b += k; } Obiektowe konwersje rozszerzające KaŜdy obiekt moŜemy przekształcić w obiekt jego (dowolnej) nadklasy. Nazywa się to konwersją rozszerzającą albo upcasting, (up - bo w górę hierarchii dziedziczenia). Obiektowe konwersje rozszerzające dokonywane są automatycznie (nie musimy stosować operatora konwersji) przy: • przypisywaniu zmiennej-referencji odniesienia do obiektu klasy pochodnej, • przekazywaniu argumentów, gdy parametr jest typu nadklasy argumentu, • zwrocie wyniku, gdy wynik podstawiamy na zmienną oznaczającą obiekt nadklasy zwracanego wyniku. Obiektowe konwersje rozszerzające static Para sum(Para pl, Para p2, Para p3) { Para p = new Para(0,0); p.add(pl); p.add(p2); p.add(p3); return p; } Para p1 = new Para(1,2); ParaInh pi1 = new ParaInh(3,4), pi2 = new ParaInh(5,6); Para wynik = sum(pp1, pi1, pi2); Zastosowanie polimorfizmu class Zwierz { String name = "nieznany"; Zwierz() {} Zwierz(String s) {name = s; } String getTyp() {return "Jakiś zwierz";} String getName() {return name;} String getVoice(){return "?";} void speak() { System.out.println( getTyp()+" "+getName()+" mówi " +getVoice()); } } class Pies extends Zwierz { Pies(){} Pies(String s) { super(s); } String getTyp() { return "Pies"; } String getVoice() { return "HAU, HAU!"; } } class Kot extends Zwierz { Kot() {} Kot(String s) { super(s); } String getTyp() { return "Kot"; } String getVoice() { return "Miauuuu..."; } } Metody i klasy abstrakcyjne Metoda abstrakcyjna nie ma implementacji (ciała) i winna być zadeklarowana ze specyfikatorem abstract. Klasa, w której zadeklarowano jakąkolwiek metodę abstrakcyjną jest klasą abstrakcyjną i musi być opatrzona kwalifikatorem abstract. abstract class SomeClass { int n; abstract int getSomething(); void say() { System.out.println("Coś tam"); } } Abstrakcyjność klasy oznacza, iŜ nie moŜna bezpośrednio, np. w wyraŜeniu new tworzyć jej egzemplarzy. Standardowe klasy Javy java.applet, java.awt, java.beans, java.io, java.lang, java.math, java.net, java.rmi, java.security, java.sql, java.text, java.util, javax.accessibility, javax.swing, org.omg.
| Pakiety
z java.util.Date data = new java.util.Date();
a import java.util.*;