Wykład 5: Więcej o Klasach i Metodach
Transkrypt
Wykład 5: Więcej o Klasach i Metodach
Wykład 5: Więcej o Klasach i Metodach Przeciążanie Metod Klasa posiada dwie lub więcej metod o tej samej nazwie ale różnych deklaracjach parametrów. Java używa liczby i typów argumentów by ustalić którą wersję metody należy wywołać. Przeciążanie metod plus dziedziczenie to sposób na implementację polimorfizmu. Demo: Przeciążanie Metod class Metody { void test() { System.out.println("Brak parametrow"); } void test(int a) { System.out.println("a: " + a); } void test(int a, int b) { System.out.println("a i b: " + a + " " + b); } double test(double a) { System.out.println("double a: " + a); return a*a; } } Demo: Przeciążanie Metod class PrzeciazanieMetod { public static void main(String args[]) { Metody m = new Metody(); double wynik; m.test(); m.test(10); m.test(10, 20); wynik = m.test(12.5); System.out.println("test(12.5): " + wynik); } } Różne Typy Wyników Różne typy wynikowe nie wystarczają: double test(double a) { System.out.println("double a: " + a); return a*a; } int test(double a) { System.out.println("double a: " + a); return (int)(a*a); } Przeciążanie i Konwersja Typów Automatyczna kowersja typów gdy nie istnieje metoda o dokładnym typie wywołania: void test() { System.out.println("Brak parametrow”); } void test(double a) { System.out.println("double a: " + a); } int i = 88; test(); test(i); Przeciążanie i Polimorfizm W językach bez przeciążania, każda metoda musi posiadać unikalna nazwę: int abs(int i) long labs(long i) float fabs(float i) Java umożliwia wystąpienie powiązanych metod pod jedną nazwą: jeden interfejs, wiele metod. static int abs(int i) static long abs(long i) static float abs(float i) Przeciążanie Konstruktorów Różne metody tworzena obiektów klasy przez przeciążanie konstruktorów. class Pudelko { double szerokosc; double wysokosc; double glebokosc; Obliczanie i wyświetlanie objętości: void objetosc() { System.out.println( szerokosc * wysokosc * glebokosc); } Przeciążanie Konstruktorów Konstruktory z trzema parametrami, z jednym parametrem, i bez parametrów. Pudelko(double s, double w, double g) { szerokosc = s; wysokosc = w; glebokosc = g } Pudelko(double b) { szerokosc = wysokosc = glebokosc = b; } Pudelko() { szerokosc = wysokosc = glebokosc = -1; } } Demo: Przeciążanie Konstruktorów class PrzeciazanieKonstruktorow { public static void main(String args[]) { Pudelko p1 = new Pudelko(10,20,15); Pudelko p2 = new Pudelko(10); Pudelko p3 = new Pudelko(); p1.objetosc(); p2.objetosc(); p3.objetosc(); } } Obiekty jako Parametry Metoda może posiadać parametry typów prostych. Można też przekazywać do metody obiekty. class Test { int a, b; Test(int i, int j) { a = i; b = j; } Czy obiekt bieżący jest równy parametrowi metody? boolean equals(Test o) { if (o.a == a && o.b == b) return true; else return false; } Demo: Przekazywanie Obiektów class PrzekazywanieObiektowMetodom { public static void main(String args[]) { Test o1 = new Test(10,20); Test o2 = new Test(10,20); Test o3 = new Test(1,1); System.out.println(“o1==o2:” +o1.equals(o2)); System.out.println(“o1==o3:” +o1.equals(o3)); } } Inicjacja Obiektu Obiektem Często przekazujemy obiekty konstruktorom: jeden obiekt inicjalizuje drugi. class Pudelko { double szerokosc; double wysokosc; double glebokosc; } Pudelko(Pudelko p) { szerokosc = p.szerokosc; wysokosc = p.wysokosc; glebokosc = p.glebokosc; } ... Demo: Inicjacja Obiektu Obiektem class PrzekazywanieObiektowKonstruktorom { public static void main(String args[]) { Pudelko p1 = new Pudelko(10,20,30); Pudelko p2 = new Pudelko(p1); } } p1.objetosc(); p2.objetosc(); Przekazywanie Argumentów Dwie metody przekazywania argumentów metodom: ● ● przez wartość: przekazanie kopii wartości argumentu - zmiany parametru formalnego nie mają wpływu na wartość argumentu wywołania przez nazwę: przekazanie odwołania do argumentu – zmiana parametru formalnego powoduje zmianę wartości argumentu wywołania Java używa obu metod. Przekazywanie Typów Prostych Przekazywanie argumentów typów prostych odbywa się przez wartość. class Test { void metoda(int i, int j) { i *= 2; j /= 2; } } Demo: Przekazywanie Typów Prostych class WywolaniePrzezWartosc { public static void main(String args[]) { Test o = new Test(); int a = 10; int b = 20; System.out.println( “przed wywolaniem: “ + a + “ “ + b); } } o.metoda(a, b); System.out.println( “po wywolaniu: “ + a + “ “ + b); Przekazywanie Obiektów Obiekty przekazywane są przez nazwę: parametr uzyskuje ten sam adres obiektu jak argument. class Test { int a, b; Test(int i, int j) { a = i; b = j; } void metoda(Test o) { o.a *= 2; o.b /= 2; } } Demo: Przekazywanie Obiektów class WywolaniePrzezNazwe { public static void main(String args[]) { Test o = new Test(10, 20); System.out.println( “przed wywolaniem: “ + o.a + “ “ + o.b); } } o.metoda(o); System.out.println( “po wywolaniu: “ + o.a + “ “ + o.b); Zwracanie Obiektów Metody mogą zwracać wartości typów prostych, jak też obiekty dowolnych klas. class Test { int a; Test(int i) { a = i; } Test doKwadratu() { Test temp = new Test(a * a); return temp; } } Demo: Zwracanie Obiektów class ZwracanieObiektow { public static void main(String args[]) { Test o1 = new Test(2); Test o2; o2 = o1.doKwadratu(); System.out.println(“o1.a: “ + o1.a); System.out.println(“o2.a: “ + o2.a); } } o2 = o2.doKwadratu(); System.out.println(“drugie wywolanie“); System.out.println(“o2.a: “ + o2.a); Rekursja Metoda rekurencyjna to metoda która wywołuje samą siebie (dla innych wartości argumentów): następuje alokacja pamięci na stosie dla zmiennych lokalnych i parametrów ● kod metody jest wywołany ponownie dla nowych wartości argumentów ● powrót powoduje usunięcie ze stosu parametrów i zmiennych, i kontynuację za punktem wywołania ● Demo: Rekursja class Silnia { int silnia(int n) { if (n == 1) return 1; return n * silnia(n-1); } } class Rekursja { public static void main(String Silnia s = new Silnia(); System.out.println(“dla 3: “ System.out.println(“dla 5: “ System.out.println(“dla 8: “ } } args[]) { + s.silnia(3)); + s.silnia(5)); + s.silnia(8)); Demo: Rekursja i Tablice class Tablica { int wartosci[]; Tablica(int i) { wartosci = new int[i]; } } void wyswietlTablice(int i) { if (i == 0) return; else wyswietlTablice(i-1); System.out.print(“[“ + (i-1) + “] “); System.out.println(wartosci[i-1]); } Demo: Rekursja i Tablice class RekursjaDlaTablic { public static void main(String args[]) { Tablica t = new Tablica(10); int i; for (i=0; i<10; i++) t.wartosci[i] = i; } } t.wyswietlTablice(10); Kontrola Dostępu Enkapsulacja umożliwia: połączenie danych i kodu, oraz kontrolę dostępu do wnętrza klasy. ● ● Zapobiega użyciu klasy w sposób niepożądany, np. aby dane były dostępne przez dostarczone metody. Umożliwia wymianę implementacji przy zachowaniu interfejsu klasy. Kontrola Dostępu Cztery specyfikatory dostępu do elementów klasy: public – dostępny dla każdej części programu ● private – tylko dla składowych danej klasy ● default – public dla składowych pakietu gdzie znajduje się element, private dla reszty ● protected – opisany później ● Specyfikator poprzedza resztę definicji elementu: private int i; public static void main(...) Demo: Kontrola Dostępu class Test { int a; public int b; private int c; void zmienC(int i) { c = i; } } int zwrocC() { return c; } Demo: Kontrola Dostępu class KontrolaDostepu { public static void main(String args[]) { Test t = new Test(); t.a = 10; t.b = 20; // t.c = 30 !BLAD! t.zmienC(30); } } System.out.print(“a, b i c: “ + t.a + “ “); System.out.println(t.b + “ “ + t.zwrocC()); Demo: Stos i Kontrola Dostępu class Stos { private int stos[] = new int[10]; private int wskaznik; Stos() { ... } void push(int element) { ... } int pop() { ... } } Statyczne Składowe Klasy Normalnie, elementy klasy (pola i metody) mogą być tylko użyte poprzez obiekty tej klasy. Elementy statyczne są niezależne od obiektów klasy: ● statyczne dane static int dane; ● statyczna metoda static void metoda(); ● statyczny blok – inicjacja elementów statycznych static { ... } Statyczne Składowe Klasy Sposób wywołania: nazwaklasy.metoda() nazwaklasy.zmienna Ograniczenia: tylko odwołania do metod i danych statycznych ● nie mogą zawierać odwołań do this czy super ● Demo: Statyczne Składowe Klasy class SkladoweStatyczne { static int a = 3; static int b; static void metoda(int x) { System.out.println(“x = + x); System.out.println(“a = + a); System.out.println(“b = + b); } //wykonywany raz gdy klasa jest ladowana static { System.out.println(“Inicjalizacja”); b = a * 4 } public static void main(String args[]) { metoda(42); } } Demo: Wywołanie Statyczne class Statyczne { static int a = 3; static int b = 99; static void wywolajMnie() { System.out.println(“a = “ + a); } } class WywolanieStatyczne { public static void main(String args[]) { Statyczne.wywolajMnie(); System.out.print(“b = “); System.out.println(Statyczne.b); } } Zmienne Final Deklaracja zmiennej jako final zapobiega zmianie jej wartości po zainicjowaniu. final int FILE_NEW = 1; final int FILE_OPEN = 2; final int FILE_CLOSE = 3; Zmienna jest faktycznie stałą. Metody są też deklarowane jako final ale znaczenie tego jest zupełnie odmienne. Tablice jako Obiekty Tablica jest zaimplementowana jako obiekt. Jednym z atrybutów tego obiektu jest length: ilość elementów które tablica może zawierać. class DlugoscTablicy { public static void main(String args[]) { int a1[] = new int[10]; int a2[] = {3, 5, 7, 9, 11, 13, 15, 17}; System.out.println(“a1: “ + a1.length); System.out.println(“a2: “ + a2.length); } } Demo: Stos Dowolnej Długości class Stos { private int stos[]; private int wskaznik; Stos(int rozmiar) { stos = new int[rozmiar]; wskaznik = -1; } void push(int element) { if (wskaznik == stos.length-1) System.out.println("Stos jest pelny."); else stos[++wskaznik] = element; } } int pop() { ... } Klasa Zagnieżdżona Klasa zagnieżdżona: definiowana wewnątrz innej klasy. Ma dostęp do wszystkich elementów, również prywatnych, klasy zewnętrznej. ● Nie jest widoczna na zewnątrz klasy zewnętrznej. ● Klasa zewnętrzna ma dostęp do klasy zagnieżdżonej, ale nie jej elementów. ● Statyczna klasa zagnieżdżona: musi odwoływać się do elementów klasy zewnętrznej przez obiekty tej klasy. Klasa Wewnętrzna Nie-statyczna klasa zagnieżdżona: ma bezpośredni dostęp do zmiennych i metod klasy zewnętrznej. class Zewnetrzna { int x = 100; class Wewnetrzna { int y = 200; void wyswietl() { System.out.println(“x = “ + x); } } Klasa Wewnętrzna void test() { Wewnetrzna w = new Wewnetrzna(); w.wyswietl(); //System.out.println(y); //!BLAD! } } class KlasaWewnetrzna { public static void main(String args[]) { //Wewnetrzna w = new Wewnetrzna(); //!BLAD! Zewnetrzna z = new Zewnetrzna(); z.test(); } }