Przygotował: Jacek Sroka 1 Programowanie obiektowe Wykłady 5 Dziedziczenie, inicjalizacja, przeciążanie metod
Przygotował: Jacek Sroka 2 Przypomnienie Typy podstawowe, klasy Pakiety Modyfikatory dostępu Działają dla klas, a nie obiektów Inicjalizacja za pomocą konstruktorów Przeciążanie metod/konstruktorów Kapsułkowanie
Przygotował: Jacek Sroka 3 Kolejność inicjalizacji class Pom1 { Pom1() { System.out.println("Pom1()"); class TestInicjalizacji { int x = 777; Pom1 p = new Pom1(); int y = f(); int f() { System.out.println("f()"); return 1; //deklaracje metod mogą się przeplatać z deklaracjami atrybutów int yy; TestInicjalizacji() { System.out.println("TestInicjalizacji()");... Kolejność: Pom1(), f(), TestInicjalizacji()
Przygotował: Jacek Sroka 4 Kolejność inicjalizacji c.d.... //kolejność deklaracji zmiennych ma znaczenie przy inicjalizacji int v = x; //int a = b; int b; //kolejność jest też istotna przy przekazywaniu parametrów //int a = b(u); int b(int u) { return u; int u; //można jednak oszukiwać (wynik: h(); w=0) int z = h(); int h() { System.out.println("h(); w="+w); return w; int w = 1313;...
Przygotował: Jacek Sroka 5 Kolejność deklaracji metod Nie jest istotna Kod jest generowany w chwili kompilacji W trakcie inicjalizacji obiektu jest tylko ciąg instrukcji pseudokodu
Przygotował: Jacek Sroka 6 Inicjalizacja statyczna Inicjalizacja składowych statycznych odbywa się jeden raz, w momencie pierwszego użycia klasy (odwołanie do składowej statycznej lub utworzenie obiektu) class InicjalizacjaStatyczna { static Pom1 p = new Pom1(); static void test() { System.out.println("test()"); InicjalizacjaStatyczna.test(); InicjalizacjaStatyczna is = new InicjalizacjaStatyczna(); Class c = InicjalizacjaStatyczna.class;
Przygotował: Jacek Sroka 7 Grupowanie inicjalizacji class BlokInicjalizacji { int x; //o wyjątkach jeszcze opowiemy { try { System.out.println("ustawiam x"); x = 7; catch (Exception e) { System.out.println("Wpadłeś jak śliwka w studzienkę kanalizacyjną"); static int y; static { int pom; pom = 1; System.out.println("ustawiam y"); y = pom; Kolejność znowu od góry na dół Przykłady użycia: odczytywanie konfiguracji z plików
Przygotował: Jacek Sroka 8 Przykład składanie kawałków tortu class A { int ia = 1; void infoa() { System.out.println("A.infoA() na obiekcie klasy " + this.getclass().getsimplename() + "\n ia="+ia); class B extends A { int ib = 2; void infob() { infoa(); System.out.println("B.infoB() na obiekcie klasy " + this.getclass().getsimplename() + "\n ia="+ia+", ib="+ib); class C extends B { int ic = 3; void infoc() { infoa(); infob(); System.out.println("C.infoC() na obiekcie klasy "...
Przygotował: Jacek Sroka 9 Wynik B składa się ze swoich składowych plus składowe A C składa się ze swoich składowych plus składowe B, czyli również składowe A C c = new C(); c.infoc(); // A.infoA() na obiekcie klasy C // ia=1 // // A.infoA() na obiekcie klasy C // ia=1 // B.infoB() na obiekcie klasy C // ia=1, ib=2 // // C.infoC() na obiekcie klasy C // ia=1, ib=2, ic=3 A a = c; System.out.println("a.iA=" + a.ia + ", c.ia=" + c.ia); //a.ia=1, c.ia=1 A co jak zmienimy nazwy atrybutów w hierarchii na takie same? W praktyce tego unikamy lub chronimy dostęp do atrybutów przy pomocy modyfikatorów dostępu
Przygotował: Jacek Sroka 10 Kompilacja vs uruchomienie Dobra intuicja dla kolejnych slajdów: Typy zmiennych są widoczne w chwili uruchomienia W chwili działania są tylko obiekty określonych typów i referencje Przypisanie na nadtyp jest zawsze bezpieczne Przypisanie na podtyp wymaga dodatkowego kodu sprawdzającego (rzutowanie)
Przygotował: Jacek Sroka 11 Dostęp do atrybutów class A { int i = 1; void infoa() { System.out.println("A.infoA() na obi...\n ia=" + i); class B extends A { int i = 2; void infob() { infoa(); System.out.println("B.infoB()...\n ia=" + ((A) this).i + ", ib="+i); //albo super.i class C extends B { int i = 3; void infoc() { infoa(); infob(); System.out.println("C.infoC()...");//nie można super.super.i
Przygotował: Jacek Sroka 12 Wynik C c = new C(); c.infoc(); // A.infoA() na obiekcie C // ia=1 // // A.infoA() na obiekcie C // ia=1 // B.infoB() na obiekcie C // ia=1, ib=2 //... // C.infoC() na obiekcie C // ia=1, ib=2, ic=3 A a = c; System.out.println("a.i=" + a.i + ", c.i=" + c.i); // a.i=1, c.i=3 Nadal podklasa ma wszystkie kawałki Rzutowanie może być niebezpieczne (wyjątek vs błąd kompilacji) chociaż akurat nie tutaj super to tak jak this referencja do bieżącego obiektu tylko że przestają być widoczne deklaracje wprowadzone przez podklasę (tylko jeden poziom wyżej) Przy odwoływaniu się do atrybutów istotny jest typ statyczny!
Przygotował: Jacek Sroka 13 Dostęp do metod class A { int i = 1; void info() { System.out.println("A.info() z ia=" + i); class B extends A { int i = 2; void info() { super.info(); System.out.println("B.info() z ia=" + ((A) this).i + ", ib=" + i); class C extends B { int i = 3; void info() { super.info();//jak wywołać info() z A? System.out.println("C.info() z ia=" + ((A) this).i +...);
Przygotował: Jacek Sroka 14 Wynik (polimorfizm) C c = new C(); c.info(); //A.info() z ia=1 //B.info() z ia=1, ib=2 //C.info() z ia=1, ib=2, ic=3 A a = c; a.info(); //A.info() z ia=1 //B.info() z ia=1, ib=2 //C.info() z ia=1, ib=2, ic=3 Przy odwoływaniu się do metod istotny jest typ dynamiczny!
Przygotował: Jacek Sroka 15 Ćwiczenie class A { void starametoda() { System.out.println("A.staraMetoda()"); void pisz() { System.out.println("A.pisz()"); class B extends A { void pisz() { System.out.println("B.pisz()"); void nowametoda() { System.out.println("B.nowaMetoda()"); pisz(); super.pisz(); Jaki będzie wynik lub czy się nieskompiluje? B b = new B(); b.starametoda(); //A.staraMetoda() b.pisz(); //B.pisz() b.nowametoda(); //B.nowaMetoda() //B.pisz() //A.pisz() A a = new B(); a.pisz(); //B.pisz() a.starametoda(); //A.staraMetoda()
Przygotował: Jacek Sroka 16 Ćwiczenie class A { void pisz() { System.out.println("A.pisz()"); void jakiewiązanie() { pisz(); B b = new B(); b.jakiewiązanie(); //B.pisz() A a = new B(); a.jakiewiązanie(); //B.pisz() class B extends A { void pisz() { System.out.println("B.pisz()");
Przygotował: Jacek Sroka 17 Ćwiczenie class A { int x = 1; B b = new B(); A a = new B(); void testzmiennej() { System.out.println(x); b.testzmiennej(); //2 //1 //1 class B extends A { int x = 2; int y = 2; void testzmiennej() { System.out.println(x); System.out.println(super.x); super.testzmiennej(); a.testzmiennej(); //2 //1 //1
Przygotował: Jacek Sroka 18 Przeciążanie metod Metody odróżniamy na podstawie nazwy i listy parametrów Nazwy jakie nadamy parametrom nie mają znaczenia, liczą się jedynie ich typy public void mojametoda(string jakaśnazwa) public void mojametoda(string innanazwa) Czasami metody wykonujemy jedynie dla ich efektów ubocznych, a zwracana wartość nas nie interesuje (więc nie służy do odróżniania metod przeciążonych) space.write(entry, transaction, lease); dodaj(4, 5); //4+5; //nie skompiluje się
Przygotował: Jacek Sroka 19 Przeciążanie i promocja wartości class PrzeciazanieMetod { void f(char x) {System.out.println("char"); void f(byte x) {System.out.println("byte"); void f(short x) {System.out.println("short"); void f(int x) {System.out.println("int"); void f(long x) {System.out.println("long"); void f(float x) {System.out.println("float"); void f(double x) {System.out.println("double"); //void f(object o) {System.out.println("Object"); //void f(string s) {System.out.println("String"); Jak będą promowane wartości? char jest promowany do int (nie do short) Dla obiektów wybierany jest typ bardziej szczegółowy pm.f('a'); pm.f((byte) 1); pm.f((short) 1); pm.f(1); pm.f(1l); pm.f(1f); pm.f(1d); pm.f(new Object()); pm.f("ala ma kota"); pm.f(null);
Przygotował: Jacek Sroka 20 Przeciążanie metod c.d. class PrzeciazanieMetod { void f(short b, int i) {System.out.println("short, int"); void f(int b, short i) {System.out.println("int, short"); //pm.f(1, 1); żadna metoda nie pasuje //pm.f((short) 1, (short) 1); pasują obie pm.f(1, (short) 1); //int, short pm.f((char) 1, (byte) 1); //int, short
Przygotował: Jacek Sroka 21 Wielodziedziczenie a przeciążanie Nie zawsze jest możliwe zdecydowanie, którą z przeciążony metod wybrać (nawet jak jest jeden parametr) void przeciążona(inta a) { void przeciążona(intb b) { PodKl p = new PodKl(); //implementowała IntA i IntB przeciążona(p); //błąd Natomiast przy uogólnianiu wybierana jest klasa najbardziej szczegółowa class NadA { class NadB extends NadA { class NadC extends NadB { static void przeciążona(nada a) {System.out.println("a"); static void przeciążona(nadb b) {System.out.println("b"); NadC c = new NadC(); przeciążona(c); //wypisze się b
Przygotował: Jacek Sroka 22 Zagadka Wymyśl dwa interfejsy, które nie mogą być naraz zaimplementowane przez jedną klasę
Przygotował: Jacek Sroka 23 Odpowiedź interface WykluczającyA { public void metoda(); interface WykluczającyB { public int metoda(); //Tak się nie da! class Wykluczanie implements WykluczającyA, WykluczającyB { public void metoda() { public int metoda() { return 0;
Przygotował: Jacek Sroka 24 Zagadka komentarz class A { class B extends A { interface NieWykluczającyA { A metoda(); interface NieWykluczającyB { B metoda(); //czemu to ma sens? class NieWykluczanie implements NieWykluczającyA, NieWykluczającyB { public B metoda() { return new B();
Przygotował: Jacek Sroka 25 Kolejność inicjalizacji Statyczne składowe nadklasy Statyczne składowe podklasy (Pełna inicjalizacja kawałka tortu odpowiadającego nadklasie) Zwykłe składowe nadklasy Konstruktor nadklasy (określony w pierwszej instrukcji konstruktora podklasy) Uwaga nad dynamiczne wiązanie (Pełna inicjalizacja kawałka tortu odpowiadającego podklasie) Zwykłe składowe podklasy Konstruktor podklasy (trzeba zacząć od wywołania konstruktora nadklasy, domyślne konstruktory może wywołać kompilator)
Przygotował: Jacek Sroka 26 Kolejność inicjalizacji (wersja oficjalna) Statyczne składowe nadklasy Statyczne składowe podklasy Zaczyna się inicjalizacja nadklasy Zaczyna się konstruktor nadklasy Wiadomo, który konstruktor podklasy użyć Zaczyna się inicjalizacja podklasy Inicjalizacja składowych podklasy Konstruktor podklasy Kończy się inicjalizacja podklasy Inicjalizacja składowy nadklasy Kontynuowanie konstruktora nadklasy
Przygotował: Jacek Sroka 27 Przykład klasa pomocnicza class Echo { static int getvalue(string s) { System.out.println("getValue(" + s + ")"); return 1; static int getvalue() { System.out.println("getValue()"); return 1;
Przygotował: Jacek Sroka 28 Przykład c.d. class A { int x = Echo.getValue("A.x"); void pisz() { System.out.println("A.pisz()"); A() { System.out.println("A()"); pisz(); B b = new B(); //getvalue(a.x) //A() //B.pisz() //getvalue(b.x) //getvalue(b.y) //B() //B.pisz() class B extends A { int x = Echo.getValue("B.x"); int y = Echo.getValue("B.y"); void pisz() { System.out.println("B.pisz()"); B() { super(); System.out.println("B()"); pisz();
Przygotował: Jacek Sroka 29 Przykład interfejsy interface MójInterfejs { int X = Echo.getValue(); public static final int Y = 2; int Z = Echo.getValue();//nieużywana stała //też zostanie //zainicjowana void róbxxx(); abstract public void róbyyy(); class MojaKlasa implements MójInterfejs { public void róbxxx() { System.out.println("róbXXX("+X+")"); public void róbyyy() { System.out.println("róbYYY("+Y+")"); MojaKlasa mk; MójInterfejs mi; mk = new MojaKlasa(); mi = mk; mi.róbyyy(); System.out.println("leniwośc"); mk.róbxxx(); //róbyyy(2) //leniwość //getvalue() //getvalue() //róbxxx(1) //prawdopodobnie 2 została //zinlinowana
Przygotował: Jacek Sroka 30 final Atrybuty Stałe kompilacji będą wplatane w wyrażenia Wartość typu podstawowego lub referencji nie może ulec zmianie Można użyć z argumentami metod Metody Nie mogą być przesłaniane Nie ma dynamicznego wiązania, czasami kompilator może wstawiać kod metody w miejsce jej wywołania (ang. inline) Klasy nie można rozszerzać
Przygotował: Jacek Sroka 31 Atrybuty final trzeba zainicjalizować class TestFinal { final int x; TestFinal() { x = 1; //inicjalizacja musi nastąpić //najpóźniej w konstruktorze
Przygotował: Jacek Sroka 32 final a private Metody private i tak nie można przesłonić, ale można zdefiniować metodę o takiej samej sygnaturze class Zagadka { // final tu nic nie zmieni private void pisz() { System.out.println("Zagadka.pisz()"); Zagadka() { pisz(); class PseudoPrzesloniecie extends Zagadka { private void pisz() { System.out.println("PseudoPrzesloniecie.pisz()"); PseudoPrzesloniecie() { pisz(); PseudoPrzesloniecie p = new PseudoPrzesloniecie(); //Zagadka.pisz() //PseudoPrzesloniecie.pisz()
Przygotował: Jacek Sroka 33 Zwalnianie zasobów W Javie nie ma żadnych jawnych bądź niejawnych destruktorów Zasoby inne niż pamięć przyjęło się zwalniać w metodzie close() (trzeba ją samemu definiować i wywoływać) plik.close(); gniazdo.close(); PołączenieZBazą.close(); Nie musimy/możemy się martwić o zwalnianie pamięci, w której przechowywane są Javowe obiekty (sterta) i zmienne (stos), bo sami jej nie przydzielamy O obiektach, których już nie będziemy potrzebować można zwyczajnie zapomnieć: { String s = "ala"; System.out.println(s);
Przygotował: Jacek Sroka 34 Odśmiecanie/Finalizacja Zwalnianiem pamięci po obiektach zajmuje się odśmiecacz Tylko obiekty niedostępne z żadnego aktywnego wątku programu Odśmiecaczem steruje JVM Programista może "podpowiedzieć : System.gc() Jeżeli pamięci jest dużo, odśmiecanie może nie być potrzebne Przed odśmieceniem danego obiektu wywoływana jest odziedziczona po Object metoda finalize() O finalize() wiadomo, że będzie wywołana co najwyżej raz, dlatego nie ma sensu zwalniać w niej jakichkolwiek zasobów Można natomiast sprawić, że obiekt stanie się ponownie dostępny Jako ćwiczenie proszę sprawdzić, czy przed odśmieceniem (po raz drugi) przywróconego obiektu finalize() będzie wywołana drugi raz Przydatne metody Runtime.getRuntime().freeMemory() i Runtime.getRuntime().totalMemory()
Przygotował: Jacek Sroka 35 Finalizacja przykład class Finalizacja { int n; String[] smieci; Finalizacja(int n) { this.n = n; smieci = new String[n]; smieci[0] = "Każda literka zaśmieca dwa bajty."; for (int i = 1; i < n; i++) smieci[i] = smieci[i - 1] + smieci[i - 1]; protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize() dla n=" + n);
Przygotował: Jacek Sroka 36 Finalizacja przykład c.d. Wywołanie: for (int i = 1; i <= 13; i++) { Finalizacja f = new Finalizacja(i); Może dać następujący wynik: finalize() dla n=9 finalize() dla n=10 finalize() dla n=12
Przygotował: Jacek Sroka 37 Parametry uruchomieniowe -Xms initial java heap size -Xmx maximum java heap size
Przygotował: Jacek Sroka 38 Jak działa odśmiecacz Odnajdywanie niedostępnych obiektów: zliczanie referencji odwołujących się do obiektu (znajdywanie grup obiektów odwołujących się do siebie nawzajem jest kosztowne) ale weak references i soft references przeglądanie sieci dostępnych (przez stos) obiektów i jakoś ich oznaczanie Porządkowanie sterty: stop-and-copy - odśmiecamy i porządkujemy (przesuwamy obiekty dbając o naprawianie referencji); strategia dobra jak dużo odśmiecania mark-and-sweep jedynie odśmiecamy; strategia dobra jak mało odśmiecania stop-and-copy można udoskonalić dzieląc stertę na bloki i umieszczając w każdym licznik jego wykorzystania Maszyna wirtualna może przełączać strategie w zależności od własności działającego programu Obecnie nie da się już przewidzieć czasu działania programu!