Programowanie w Javie wykład 7 Klasy c.d. (przeciążanie metod, polimorfizm) Metody i klasy abstrakcyjne Bloki inicjalizacyjne

Podobne dokumenty
Aplikacje w Javie wykład 5 Klasy c.d. (przeciążanie metod, polimorfizm) Metody i klasy abstrakcyjne Interfejsy

Programowanie w środowisku graficznym- wykład 5 Klasy c.d. (przeciążanie metod, polimorfizm) Metody i klasy abstrakcyjne Interfejsy

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Kompozycja i dziedziczenie klas

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Dziedziczenie. dr Jarosław Skaruz

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Polimorfizm. dr Jarosław Skaruz

Dziedziczenie. Tomasz Borzyszkowski

Wykład 6: Dziedziczenie

Programowanie obiektowe i zdarzeniowe

Programowanie w Javie wykład 8 Interfejsy

Definiowanie własnych klas

Enkapsulacja, dziedziczenie, polimorfizm

Klasy abstrakcyjne, interfejsy i polimorfizm

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Wykład 8: klasy cz. 4

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Dokumentacja do API Javy.

Java podstawy jęyka. Wykład 2. Klasy abstrakcyjne, Interfejsy, Klasy wewnętrzne, Anonimowe klasy wewnętrzne.

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Związek między pojęciami Zasada podstawialności Podklasy muszą realizować kontrakt zawarty przez nadklasy

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie obiektowe

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

Programowanie w Javie - wykład 3

Rozdział 4 KLASY, OBIEKTY, METODY

Programowanie obiektowe

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Wykład 5: Klasy cz. 3

.NET Klasy, obiekty. ciąg dalszy

Dziedziczenie i interfejsy

Wykład 7: Pakiety i Interfejsy

Klasy abstrakcyjne i interfejsy

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Technologie i usługi internetowe cz. 2

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Programowanie w Internecie. Java

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

TEMAT : KLASY DZIEDZICZENIE

Aplikacje w środowisku Java

Projektowanie obiektowe. Roman Simiński Polimorfizm

PARADYGMATY PROGRAMOWANIA Wykład 4

Kurs WWW. Paweł Rajba.

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Definicje klas i obiektów. Tomasz Borzyszkowski

PHP 5 język obiektowy

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Programowanie obiektowe - 1.

Języki i metody programowania Java. Wykład 2 (część 2)

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Programowanie obiektowe

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

Dziedziczenie jednobazowe, poliformizm

Co to jest klasa? Z programistycznego punktu widzenia klasa stanowi typ danych, który odwzorowuje wspólne cechy jakiegoś obiektu.

Wykład 5 Okna MDI i SDI, dziedziczenie

JAVA- wykład 2 Klasy

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Programowanie obiektowe

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Programowanie w środowisku graficznym- wykład 2 Java - Klasy

Język JAVA podstawy. Wykład 4, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Typy klasowe (klasy) 1. Programowanie obiektowe. 2. Założenia paradygmatu obiektowego:

Podstawy Programowania Obiektowego

Programowanie w Javie - wykład 4

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Mechanizm dziedziczenia

Wykład 9: Polimorfizm i klasy wirtualne

Marcin Luckner Politechnika Warszawska Wydział Matematyki i Nauk Informacyjnych

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Podstawa: Bruce Eckel, Thinking in Java, Second Ed., Prentice Hall, 1998 The JavaLanguage Environment, A white Paper, Sun, Oct.

Wykład 4: Klasy i Metody

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Do czego służą klasy?

10. Programowanie obiektowe w PHP5

Kompozycja i dziedziczenie klas

Podstawy Języka Java

Wykład 5: Więcej o Klasach i Metodach

Interfejsy i klasy wewnętrzne

Platformy Programistyczne Podstawy języka Java

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Programowanie obiektowe w języku

Programowanie obiektowe

Diagramy klas. dr Jarosław Skaruz

Wykład 8: Obsługa Wyjątków

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Programowanie 2. Język C++. Wykład 9.

Definiowanie własnych klas

Obiektowość mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2012

Języki i metody programowania Java INF302W Wykład 2 (część 1)

Programowanie obiektowe

Dawid Gierszewski Adam Hanasko

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Programowanie obiektowe

Transkrypt:

1 Programowanie w Javie wykład 7 Klasy c.d. (przeciążanie metod, polimorfizm) Metody i klasy abstrakcyjne Bloki inicjalizacyjne Treści prezentowane w wykładzie zostały oparte o: Barteczko, JAVA Programowanie praktyczne od podstaw, PWN, 2014 Barteczko, JAVA Uniwersalne techniki programowania, PWN, 2017 http://docs.oracle.com/javase/8/docs/ C. S. Horstmann, G. Cornell, Java. Podstawy, Helion, Gliwice 2013 S. Stępniak JDK 8 WPROWADZENIE DO WYBRANYCH ZAGADNIEŃ

Dziedziczenie - przedefiniowanie metod Przedefiniowanie (nadpisywanie) metody (ang. overriding) nadklasy w klasie pochodnej oznacza dostarczenie w klasie pochodnej definicji nieprywatnej i niestatycznej metody z taką samą sygnaturą (czyli nazwą i listą parametrów) jak sygnatura metody nadklasy, ale z ewentualnie inną definicją ciała metody, przy czym: typy wyników tych metod muszą być takie same lub kowariantne (co oznacza m.in., że typ wyniku metody z podklasy może być podtypem wyniku metody nadklasy), przedefiniowanie nie może ograniczać dostępu: specyfikator dostępu metody przedefiniowanej w podklasie musi być taki sam lub szerszy (np. public zamiast protected) niż metody przedefiniowywanej, metoda przedefiniowana (z podklasy) nie może zgłaszać więcej lub bardziej ogólnych wyjątków kontrolowanych niż metoda przedefiniowywana (z nadklasy). 2

3 Dziedziczenie - przedefiniowanie metod Istotą przedefiniowania jest modyfikacja, uszczegółowienie funkcjonalności. Jest to wielka zaleta, bez tego programowanie obiektowe nie byłoby możliwe. Aby uniknąć możliwości popełniania podobnych błędów w przypadkach, gdy zmiany funkcjonalności fragmentów kodu nie są potrzebne, czy też są nawet niebezpieczne, w deklaracji metod stosuje się słowo kluczowe final. Słowo to użyte w deklaracji metody zabrania jej przedefiniowania. Uwaga: Przy przedefiniowaniu metod używajmy adnotacji @Override class Thought { public void message() { System.out.println("I like holidays"); public class Advice extends Thought { @Override // adnotacja @Override jest opcjonalna public void message() { System.out.println("Don't worry be happy"); super.message();// metoda z nadklasy

Przedefiniowanie i klauzula throws 4 Przedefiniowanie metody nie może poszerzać zakresu wyjatków kontrolowanych wymienionych w klauzuli throws ( wyjątki kontrolowane, to te których klasy są pochodne od klasy Exception, ale nie RuntimeException). Oznacza to, że: jeżeli metoda z klasy bazowej nie ma klauzuli throws, to metoda przedefiniowująca ją w klasie pochodnej nie może wymienić w swojej klauzuli throws żadnych wyjątków kontrolowanych, jeżeli metoda z klasy bazowej wymienia w swojej klauzuli throws jakieś wyjatki kontrolowane, to metoda przedefiniowująca ją w klasie pochodnej nie może wymienić żadnej nadklasy tych wyjątków ani żadnych dodatkowych innych klas wyjątków kontrolowanych, może natomiast wymienić dowolne wyjątki pochodzące z podklas wyjątków, zgłaszanych przez metodę z klasy bazowej, niezależnie od metody z klasy bazowej metoda przedefiniowana w klasie pochodnej może nie zgłaszać żadnych wyjatków i nie mieć klauzuli throws, metoda przedefiniowana w klasie pochodnej zawsze może zgłaszać wyjatki niekontrolowane i ewentualnie wymieniać je w swojej klauzuli throws

5 Przykład: class A { Przedefiniowanie i klauzula throws void met1() throws Exception { void met2() throws IOException { void met3() throws Exception { void met4() { class B extends A { void met1() throws IOException { //wyjątek IOException jest pochodny od Exception void met2() throws FileNotFoundException, IOException { //FileNotFoundException jest pochodny od IOException, void met3() { void met4() throws NumberFormatException { // NumberFormatException jest pochodny od RuntimeException

Przedefiniowywanie i przeciążanie metod 6 Przedefiniowanie (nadpisywanie) metod (overriding) należy odróżniać od przeciążania metod (overloading) Metody przeciążone mają po prostu te same nazwy, ale inną liczbę i/lub typy parametrów. Zwróćmy uwagę, że: po pierwsze, przeciążone metody mogą należeć do tej samej lub różnych klas (z których jedna pośrednio lub bezpośrednio dziedziczy inną), po drugie przeciążanie nie wyklucza przedefiniowania: jeśli np. w klasie A zdefiniowano dwie publiczne metody z tą samą nazwą (co oznacza, że są one przeciążone, bo sygnatury metod deklarowanych w jednej klasie muszą się różnić), to w klasie B dziedziczącej klasę A możemy je dodatkowo przeciążyć (czyli podać w deklaracji inny zestaw parametrów) oraz przedefiniować (pozostawiając sygnaturę bez zmian i dostarczając innej definicji kodu metody). Metoda prywatna nigdy nie może być przedefiniowana w podklasie. Deklaracja w podklasie metody o tej samej sygnaturze co metoda prywatna nadklasy oznacza praktycznie wprowadzenie "niezależnego" bytu do naszego programu (zatem możemy tu już mieć np. całkiem inny typ wyniku niż w metodzie prywatnej o tej samej sygnaturze z nadklasy).

Pokrywanie metod (hiding) 7 Pokryciem metody nazywa się dostarczenie w podklasie definicji metody statycznej o tej samej sygnaturze i tym samym lub kowariantnym typem wyniku jak metoda statyczna z nadklasy. Pokrywanie (hiding) nie dotyczy metod niestatycznych, co więcej jeśli w podklasie dostarczymy definicji metody statycznej o tej samej sygnaturze jak metoda niestatyczna nadklasy, to wystąpi błąd w kompilacji. Pokrywanie może dotyczyć również pól: oznacza ono wtedy deklarację w podklasie pola o takim samym identyfikatorze jak pole z nadklasy. Pokrycie identyfikatorów pól różni się zarówno od pokrywania identyfikatorów metod jak i przedefiniowania metod. Pole statyczne może pokryć pole niestatyczne i odwrotnie. Pole pokrywające pole nadklasy może mieć całkiem inny typ niż pokryte pole nadklasy. Odwołania do przedefiniowanych metod oraz pokrytych metod i pól nadklasy z poziomu metod podklasy realizowane są za pomocą konstrukcji: super.odwołanie_do_składowej

Metody wirtualne. Polimorfizm 8 Przypomnijmy, że obiekt klasy pochodnej posiada wszystkie atrybuty i metody klasy bazowej, a więc zawiera w sobie obiekt klasy bazowej (nadklasy). Dlatego odniesienie do takiego obiektu można zapamiętać w zmiennej referencyjnej klasy bazowej. class A { class B extends A { public class TestAB{ A ob1 = new A(); A ob2 = new B(); Jeśli w podklasie (klasie pochodnej) zostanie przedefiniowana jakaś metoda, zdefiniowana pierwotnie w nadklasie (klasie bazowej), to przy wywołaniu tej metody zostanie uruchomiona metoda tej klasy, do której faktycznie należy obiekt, a nie tej klasy która jest typem zmiennej referencyjnej zawierającej odniesienie do obiektu. Oznacza to, że wiązanie odwołań do metod z kodem programu następuje nie w czasie kompilacji programu, lecz fazie wykonania programu tuż przed każdorazowym wykonaniem instrukcji wywołującej przedefiniowaną metodę.

Metody wirtualne. Polimorfizm 9 class A { //... void fun() { System.out.println("Jestem z nadklasy"); //... class B extends A { // @Override void fun() { System.out.println("Jestem z podklasy"); // public class TestAB{ public static void main(string[] args) { A ob1 = new A(); A ob2 = new B(); ob1.fun();//jestem z nadklasy ob2.fun();//jestem z podklasy

Metody wirtualne. Polimorfizm 10 Metody wirtualne to takie metody, dla których wiązanie odwołań z kodem programu następuje w fazie wykonania programu. Nazywa się to "dynamic binding" lub "late binding". W Javie wszystkie metody są wirtualne za wyjątkiem: metod statycznych (bo nie dotyczą obiektów, a klasy) metod deklarowanych ze specyfikatorem final, który oznacza, że metoda jest ostateczna i nie może być przedefiniowana, metod prywatnych (bo metody prywatne nie mogą zostać przedefiniowane). Mówi się, że odwołania do metod wirtualnych są polimorficzne, a słowo "polimorficzne" używane jest w tym sensie, iż konkretny efekt odwołania może przybierać różne kształty, w zależności od tego jaki jest faktyczny typ obiektu, na rzecz którego wywołano metodę wirtualną. Thought mysl1 = new Thought(); mysl1.message(); // "I like holidays" mysl1 = new Advice(); mysl1.message(); //"Don't worry be happy" - polimorfizm

Polimorfizm - przykład class Pojazd { public void ruszaj() { System.out.println("Pojazdy służą do " + "przemieszczania się "); class Auto extends Pojazd { @Override public void ruszaj() { super.ruszaj(); // wywołanie metody nadklasy System.out.println("Auto to wygodny środek transportu"); public class TestAuto { public static void main (String args []){ Pojazd b = new Auto (); // ref. do Pojazdu, ale obiekt Auto b.ruszaj(); //wywoła metodę z klasy Auto Output: Pojazdy służą do przemieszczania się Auto to wygodny środek transportu 11

Polimorfizm - przykład Rozważmy klasę Zwierz opisującą takie właściwości różnych zwierząt jak: nazwa rodzaju, sposób komunikowania się ze światem oraz imię. class Zwierz { private String imie = "bez imienia"; Zwierz() { Zwierz(String imie) { this.imie = imie; String zwrocgatunek(){ return "Jakis zwierz"; final String zwrocimie(){ return imie; String dajglos(){ return "?"; //Metoda "mowa" symuluje wydanie głosu //wypisując odpowiedni komunikat void mowa() { System.out.println(zwrocGatunek()+" " +zwrocimie()+" mówi "+dajglos()); 12

Polimorfizm - przykład 13 Dla bazowej klasy Zwierz zdefiniujmy klasy pochodne Pies i Kot: class Pies extends Zwierz { Pies() { Pies(String imie) { super(imie); @Override String zwrocgatunek() { return "Pies"; @Override String dajglos(){ return "HAU, HAU!";

Polimorfizm - przykład 14 class Kot extends Zwierz { Kot(){ Kot(String imie) { super(imie); @Override String zwrocgatunek() { return "Kot"; @Override String dajglos(){ return "Miauuuu...";

Polimorfizm - przykład W klasie TestPolimorfizm wypróbujemy naszą hierarchię klas zwierząt przy symulowaniu rozmów pomiędzy poszczególnymi osobnikami. Rozmowę symuluje statyczna funkcja rozmowazwierzat, która ma dwa argumenty obiekty typu Zwierz, oznaczające aktualnych rozmówców. public class TestPolimorfizm{ static void rozmowazwierzat(zwierz z1, Zwierz z2) { z1.mowa(); z2.mowa(); System.out.println("--------------------------------"); public static void main(string[] arg) { Zwierz z1 = new Zwierz(),z2 = new Zwierz(); Pies pies = new Pies(), kuba = new Pies("Kuba"), reksio = new Pies("Reksio"); Kot kot = new Kot(); rozmowazwierzat(z1, z2); rozmowazwierzat(kuba, reksio); rozmowazwierzat(kuba, kot); rozmowazwierzat(reksio, pies); 15

Polimorfizm - przykład 16 W wyniku wykonania programu otrzymamy: Jakis zwierz bez imienia mówi? Jakis zwierz bez imienia mówi? ---------------------------------------- Pies Kuba mówi HAU, HAU! Pies Reksio mówi HAU, HAU! ---------------------------------------- Pies Kuba mówi HAU, HAU! Kot bez imienia mówi Miauuuu... ---------------------------------------- Pies Reksio mówi HAU, HAU! Pies bez imienia mówi HAU, HAU! ---------------------------------------- Podsumowując polimorfizm polega na tym, że metoda mowa(), określona w klasie Zwierz, dzięki wirtualności metod zwrocgatunek() i dajglos() działa prawidłowo dla różnych zwierząt (obiektów podklas klasy Zwierz).

Polimorfizm przykład Z polimorfizmem spotkaliśmy się już wielokrotnie korzystając z metody tostring(), która jest po raz pierwszy zdefiniowana w klasie Object: public class Object{ //tostring()- zwraca id obiektu jako napis //nazwa_klasy@unikalny_identyfikator_obiektu. Klasę Object dziedziczą wszystkie klasy (pośrednio lub bezpośrednio). W klasach tych można więc zawsze przedefiniować metodę tostring(). A przedefiniowane metody wołane są polimorficznie - zawsze więc uzyskamy właściwy opis obiektu (określony w danej klasie), lub - jeśli nie zdefiniowano w niej metody tostring - opis z pierwszej nadklasy, w której jest ona zdefiniowana, np. public class Para{ int a,b; @Override public String tostring(){ return "(" + a + "," + b + ")"; Pamiętajmy, że przedefiniowanie metody wymaga, aby miała ona identyczną sygnaturę i identyczny (lub kowariantny) typ wyniku jak metoda z nadklasy, a także by nie ograniczała jej widzialności (dostępu). 17

Metody i klasy abstrakcyjne Metoda abstrakcyjna to metoda, która nie ma implementacji (ciała) i jest zadeklarowana ze specyfikatorem abstract. abstract int getsomething(); //nie ma ciała {, tylko ; Klasa, w której zadeklarowano jakąkolwiek metodę abstrakcyjną jest klasą abstrakcyjną i musi być opatrzona specyfikatorem abstract. Klasa abstrakcyjna może (ale nie musi) zawierać metody abstrakcyjne. Wystarczy zadeklarować ją ze specyfikatorem abstract. abstract class SomeClass { int n; abstract int getsomething(); void say() { System.out.println("Coś tam, coś tam"); Nie można tworzyć obiektów klasy abstrakcyjnej. Klasa abstrakcyjna może być dziedziczona przez nowe klasy. Klasa pochodna powinna przedefiniować (a właściwie zdefiniować) wszystkie metody abstrakcyjne, które odziedziczyła z abstrakcyjnej klasy bazowej. W przeciwnym wypadku klasa pochodna nadal pozostanie klasą abstrakcyjną i nie będzie można tworzyć jej obiektów. 18

Metody i klasy abstrakcyjne Metody abstrakcyjne to takie, co do których nie wiemy jeszcze jaka może być ich konkretna implementacja, ale wiemy, że powinny wystąpić w zestawie metod każdej konkretnej klasy dziedziczącej klasę abstrakcyjną. Konkretna implementacja (definicja w klasie kodu metody) może być bardzo różna, w zależności od konkretnego rodzaju obiektów, które opisuje dana klasa. Przykład. Rozważmy klasę Figura, reprezentującą dowolną figurę geometryczną, którą można narysować i zmazać. Przyjmiemy, ze chociaż figury rysuje się różnie, to ściera się je tak samo. Dla zapewnienia wspólnego interfejsu dla wszystkich figur metody rysuj() i zmaz() powinny być zadeklarowane w klasie Figura. Ponieważ nie można narysować ogólnej figury, to metoda rysuj będzie abstrakcyjna. Poza tym, ogólne figury nie istnieją, zatem klasa Figura nie powinna w ogóle mieć instancji (każdy obiekt klasy Figura musi być jakąś konkretną figurą, obiektem jakiejś klasy pochodnej) public abstract class Figura { public abstract void rysuj(); public void zmaz() { System.out.println("Figura zmazana"); 19

Metody i klasy abstrakcyjne W definicji klasy pochodnej po klasie Figura musimy przedefiniować metodę rysuj(), zaś metodę zmaz() możemy, ale nie musimy, gdyż nie jest ona abstrakcyjna. class Trojkat extends Figura { private int wysokosc; public Trójkat(int wysokosc) { this.wysokosc = wysokosc; @Override public void rysuj() { for (int i = 0; i < wysokosc; i++) { for (int j = 0; j < wysokosc - i; j++) System.out.print( ); for (int j = 0; j < i * 2-1; j++) System.out.print( ^ ); System.out.println(); 20

Metody i klasy abstrakcyjne 21 Wówczas możemy używać tej klasy jak poniżej: Trojkat t = new Trojkat(7); Figura f = new Trojkat(3); //! Figura g = new Figura(); // nie można tworzyć instancji t.rysuj(); t.zmaz(); f.rysuj(); Oczywiście należy pamiętać, że referencje do obiektu typu Trojkat możemy przechowywać w zmiennej typu Figura, co wcale nie oznacza, że obiekt f z powyższego listingu jest klasy Figura jest on klasy Trojkat.

Bloki inicjacyjne (ang. initialization blocks) 22 W Javie zasadniczo nie można używać instrukcji sterujących poza ciałami metod i konstruktorów. Od tej zasady istnieją dwa wyjątki, a mianowicie użycie: niestatycznego bloku inicjacyjnego (inicjującego lub inicjalizacyjnego) statycznego bloku inicjacyjnego (inicjującego lub inicjalizacyjnego) Niestatyczny blok inicjacyjny wprowadzamy ujmując kod wykonywalny w nawiasy klamrowe i umieszczając taką konstrukcję w definicji klasy poza ciałem jakiejkolwiek metody (czy konstruktora). Kod bloku zostanie wykonany na etapie inicjacji obiektu, czyli przy tworzeniu obiektu, przed wywołaniem konstruktora. Taka możliwość może okazać się przydatna, gdy mamy kilka konstruktorów i chcemy wyróżnić pewien kod, który będzie inicjował obiekt niezależnie od użytego konstruktora i przed użyciem jakiegokolwiek z nich. Jeśli blok inicjujący zgłasza wyjątek, to musi on być zadeklarowany w klauzuli throws każdego konstruktora. Bloki inicjujące mogą zawierać dowolne instrukcje (np. pętle). Można zdefiniować wiele bloków inicjujących (ale nie należy tego robić, ze względu na czytelność).

23 Bloki inicjacyjne (inicjujące) -przykład class A { final static int n = 10; int tab[] = new int[n]; { //Blok inicjujący tablicę, nie musimy tej inicjacji //wpisywać do poszczególnych konstruktorów. //Można to osiągnąć przy pomocy odpowiedniej metody. for(int i=0; i<n; i++) tab[i] = i; System.out.println("Inicjalizacja"); //Wywołanie metod też jest dozwolone //konstruktory A() { //... A(int i) { //...

Bloki inicjacyjne 24 Bloki inicjujące są przydatne: w klasach anonimowych, bo tam nie da się zdefiniować konstruktora, instrukcje w bloku inicjującym mogą inicjować zmienne final, czego nie można zrobić w treści metody. Statyczne (klasowe) bloki inicjacyjne. Można też definiować bloki inicjujące wykonujące się przy tworzeniu klasy (a nie obiektu). Czyli dokonujące inicjacji na rzecz całej klasy. Ich deklaracja wygląda tak samo jak w przypadku zwykłych (egzemplarzowych) bloków inicjujących, tyle że cały blok poprzedza słowo static. Oczywiście nie ma w nim dostępu do zmiennych egzemplarzowych. W tych blokach nie można także zgłaszać sprawdzalnych wyjątków (bo nie ma gdzie ich przechwytywać). Korzystamy z nich, gdy pojawia się potrzeba wykonania jakiegoś kodu jeden raz, przy pierwszym odwołaniu do klasy (np. użyciu metody statycznej lub stworzeniu pierwszego obiektu). Przy inicjacji pól statycznych możemy skorzystać z dowolnych wyrażeń, składających się ze zmiennych i stałych statycznych oraz z wywołań statycznych metod, ale - oczywiście - nie sposób użyć instrukcji wykonywalnych (np. sterujących).

REGUŁY INICJACJI Inicjacja klasy powoduje jednokrotne zainicjowanie elementów statycznych tzn. najpierw wszystkie pola statyczne uzyskują wartości domyślne, a następnie wykonywane są inicjatory statyczne (tzn. inicjatory pól statycznych oraz statyczne bloki inicjacyjne) w kolejności ich występowania w klasie. Inicjacja klasy następuje w wyniku jej załadowania przez JVM, co może się zdarzyć przy uruchomieniu głównej klasy programu lub pierwszym odwołaniu z programu do innej klasy na skutek odwołania do składowej statycznej Tworzenie każdego obiektu (new) powoduje nadanie niestatycznym polom klasy wartości domyślnych (0, false dla typu boolean, null dla referencji), następnie wykonanie inicjatorów niestatycznych w kolejności ich występowania w klasie, po czym wykonywany jest konstruktor. W momencie tworzenia jakiegokolwiek obiektu wszystkie pola statyczne są już zainicjowane i zostały już wykonane wszystkie inicjatory statyczne. W inicjatorach statycznych można odwoływać się do wszystkich statycznych metod klasy, ale tylko do tych statycznych pól, których deklaracje poprzedzają inicjator. W inicjatorach niestatycznych można odwoływać się do wszystkich metod klasy, do wszystkich pól statycznych (niezależnie od miejsca ich występowania), ale tylko do tych pól niestatycznych, których deklaracje poprzedzają inicjator. W konstruktorze można odwoływać się do wszystkich metod i pól klasy (są już zainicjowane). 25

public class InitOrder { REGUŁY INICJACJI private static int s = 100; private static final int C; private int a = 1; InitOrder() { report("konstruktor: s, C, a, b mają wartości :", s, C, a, b); private int b = 2; { report("blok inicjacyjny: s, C, a =", s, C, a); static { report("statyczny blok inicjacyjny, zmienna s = ", s); C = 101; // opóźniona inicjacja stałej! private static void report(string msg, int... args ) { System.out.print(msg + " "); for (int i : args) { System.out.print(i + " "); System.out.println(); public static void main(string[] args) { report("wywołanie metody main"); new InitOrder();new InitOrder(); 26

REGUŁY INICJACJI 27 W wyniku zostanie wyprowadzony kod: Statyczny blok inicjacyjny, zmienna s = 100 Wywołanie metody main Blok inicjacyjny: s, C, a = 100 101 1 Konstruktor: s, C, a, b mają wartości : 100 101 1 2 Blok inicjacyjny: s, C, a = 100 101 1 Konstruktor: s, C, a, b mają wartości : 100 101 1 2 Podsumowując: najpierw - i tylko raz - inicjowane są kolejno pola statyczne, a przy każdym tworzeniu obiektu - kolejno - pola niestatyczne.