Object Orientation
W tym temacie napiszemy trochę zasad jakie obowiązują w Javie. Zasad nigdy nie za wiele więc poruszymy też takie tematy jak nadpisywanie i przeciążanie metod. Zresztą czytając notatki będzie wiadomo do czego one się tyczą. Niom i na koniec krótki test, aby sprawdzić czy się nadajemy aby pójść dalej.
Wiec zaczynamy.
Enkapsulacja zwana również hermetyzacją, relacje IS-A, HAS-A
- Enkapsulacja pomaga chować implementacje za interfejsem lub API
- Enkapsulacja ma dwie funkcje:
- Zmienne klasowe są chronione, głównie poprzez użycie modyfikatora
private
- Dostęp do zmiennych zapewniają setter'y i getter'y
- Zmienne klasowe są chronione, głównie poprzez użycie modyfikatora
- Relacja IS-A odnosi się do dziedziczenia lub implementacji (interfejsy)
- IS-A jest wyrażana przy pomocy słów kluczowych
extends, implements
- IS-A, "dziedziczy z", lub "jest podtypem" są tymi samymi sposobami przedstawienia relacji typu IS-A
- HAS-A oznacza że klasa posiada "ma" referencje do instancji innej klasy lub innej instancji tej samej klasy
Dziedziczenie
- Dziedziczenie pozwala klasie być podklasą danej klasy zwanej super klasą i w ten sposób klasa dziedziczy publiczne i chronione zmienne i metody super klasy.
- Dziedziczenie jest kluczowym pojęciem które leży u podstaw IS-A, polimorfizmu, nadpisywania, przeciążania i rzutowania.
- Wszystkie klasy z wyjątkiem klasy Object, są podklasami klasy Object czyli są typu Object, dlatego dziedziczą one metody klasy Object
Polimorfizm
- Polimorfizm oznacza "wiele form"
- Zmienne referencyjne są zawsze jednego, niezmiennego typu, ale mogą odnosić się do podtypu obiektu
- Pojedynczy obiekt może się odnosić do zmiennej referencyjnej wielu różnych typów, tak długo aż są tego samego typu, albo są super typem obiektu
- Typ zmiennej referencyjnej określa (nie typ obiektu), która metoda może być wywołana
- Polimorficzne wywołanie metody odnosi się tylko do nadpisanych "instancji" metod
Overriding i Overloading
- Metody mogą być nadpisywane lub przeciążane; konstruktor może być przeciążany, ale nie nadpisywany
- Metody abstrakcyjne muszą być nadpisane poprze pierwszą konkretną podklasę (nie abstrakcyjną)
- Zasady nadpisywania metod:
- Muszą mieć tą samą listę argumentów
- Muszą zwracać ten sam typ, od Javy 5 typ zwracany może być podtypem, znane to pojęcie jest jako przykrywanie typu zwracanego (covariant return)
- Nie może mieć silniejszego modyfikatora dostępu jak ma public nie możemy nadpisać metody jako protected
- Może mieć słabszy modyfikator dostępu jak ma protected możemy nadpisać dając public
- Nie może rzucać nowego lub wyższego typu wyjątku (wyjątku tak zwanego checked exception)
- Może rzucać niższą podklasą wyjątku, lub może rzucać jakikolwiek wyjątek runtime'u (zwane one są unchecked exception)
final
metody oznaczone tym słowem nie mogą być nadpisywane- Tylko dziedziczone metody mogą być nadpisywane, i należy zawsze pamiętać że metody oznaczone słowem
private
nigdy nie są dziedziczone - Jeżeli chcemy wywołać wersje metody nadpisanej z super klasy używamy słowa
super.nadpisanaMetoda()
- Przeciążanie metod oznacza ponowne użycie nazwy metody, ale z inna lista argumentów
- Przeciążane metody:
- Muszą mieć różną listę argumentów
- Mogą zwracać różne typy, jeżeli lista argumentów jest różna
- Mogą mieć różne modyfikatory dostępu
- Mogą rzucać różnymi wyjątkami
- Metody z nad klasy mogą być przeciążane
- Polimorfizm tyczy się tylko NADPISANYCH metod, nie ma nic wspólnego z przeciążaniem
- typ obiektu (nie typ referencji) określa która metoda jest używana w czasie wykonania runtime'u
- Typ referencji określa która metoda będzie używana podczas kompilowania - compile time
Zmienne referencyjne - rzutowanie
- Są dwa typy rzutowania zmiennych referencyjnych: rzutowanie w dół i rzutowanie w górę
- Rzutowanie w dół (Downcasting): Jeśli mamy referencję która wskazuje na podtyp obiektu, możemy ją przypisać do zmiennej referencyjnej podtypu. Musimy zaznaczyć rzutowanie jeśli chcemy je wykonać. Rezultatem tego jest że za pomocą tej zmiennej mamy dostęp do składowych podtypu.
- Rzutowanie w górę (Upcasting): możemy przypisać referencje do nad typu, zaznaczając rzutowanie lub też nie. Jest to bezpieczna operacja i nie potrzebujemy sygnalizować tego kompilatorowi.
Implementowanie interfejsów
- Jeśli zaimplementujemy interfejs musimy uwzględnić wszystko co zawiera interfejs
- Implementując interfejs musimy nadpisać wszystkie metody zdefiniowane w interfejsie
- jedna klasa może implementować wiele interfejsów
Typ zwracany
- Przeciążane metody mogą zmieniać typ zwracany przez metodę, nadpisywane metody nie mogą z wyjątkiem pokrywania zwracanego typu (podklasa typu)
- Referencja obiektu może akceptować
null
jako zwracaną wartość - Tablica jest legalnym typem który możemy zwracać, w obu przypadkach czy przy deklaracji czy przy zwracaniu wartości
- Dla metod zwracających prymitywny typ danych, jakakolwiek wartość może być domyślnie przeliczona do typu zwracanego
- Nic nie może być zwracane z typu
void
, ale możemy zwrócić nic znaczy możemy zdefiniować samo słoworeturn;
np. przy pomocy tego słowa możemy opuścić metodę wcześniej, ale nie możemy zwracać nic z metod z określonym typem - Metody zwracające referencję mogą zwrócić podtyp
- Metody zwracające typ interfejsu mogą zwracać jakikolwiek typ implementujący ten interfejs
Konstruktory i instancje
- Konstruktor jest zawsze wywoływany gdy nowy obiekt jest tworzony
- Każda nad klasa w drzewie dziedziczenia będzie miała wywołany konstruktor
- Każda klasa nawet abstrakcyjna ma przynajmniej jeden konstruktor
- Konstruktor musi mieć tą samą nazwę co klasa
- Konstruktor nie posiada typu zwracającego. Jeśli zobaczy się kod zwracający typ, to musi być to metoda o tej samej nazwie co klasa nie konstruktor
- Po wywołaniu konstruktora następują:
- Konstruktor wywołuje konstruktor swojej nad klasy, która z kolei wywołuje konstruktor swojej nad klasy i tak dalej aż dojdzie do klasy Object
- Następnie wykonuje się konstruktor klasy Object i powraca do konstruktora który wywołał ten konstruktor, aż dojdzie do konstruktora który wywołał całą procedurę
- Konstruktor może używać jakiegokolwiek modyfikatora dostępu nawet
private
- Kompilator utworzy za nas domyślny konstruktor tylko wtedy jeśli nie zostanie zdefiniowany żaden inny konstruktor
- Domyślny konstruktor nie posiada argumentów i wywołuje bez-argumentowy konstruktor nad klasy
super()
- Pierwszy deklaracja każdego konstruktora musi wywoływać bądź
this()
przeciążony konstruktor albosuper()
- Kompilator sam doda
super()
chyba że samemu się już zadeklarowało wywołaniethis()
lubsuper()
- Składowe klasy są dopiero dostępne kiedy super konstruktor zakończy działanie
- Klasy abstrakcyjne mają konstruktor który jest wywoływany kiedy konkretna klasa jest tworzona (instancja)
- Interfejsy nie posiadają konstruktora
- Jeżeli twoja nad klasa nie posiada konstruktora bez-argument-owego, musisz utworzyć konstruktor i wywołać
super()
z odpowiednią listą argumentów - Konstruktor nigdy nie może być odziedziczony, dlatego konstruktor też nigdy nie może zostać nadpisany
- Konstruktor może być tylko wywołany bezpośrednio przez inny konstruktor, (bez słowa new) wywołując
this()
lubsuper()
- Problemy z wywoływaniem
this()
- Może być wywoływany tylko jako pierwsza deklaracja konstruktora
- Lista argumentów decyduje który przeciążony konstruktor zostanie wywołany
- Konstruktor może wywoływać inny konstruktor i tak w kółko, ale lepiej żeby w końcu wywołać
super()
bo wystąpi stack overflow - Wywołanie
super()
ithis()
nie może mieć miejsca w tym samym konstruktorze, możemy mieć tylko jeden albo this albo super nigdy obydwu
Static
- Używamy tylko metod statycznych tylko do implementowania zachowań które nie mają wpływu na na stany żadnych instancji
- Używamy zmiennych statycznych tylko do przechowywania danych które są specyfikacja dla klasy przeciwieństwie do specyfikacji zmiennych niestatycznych, będzie tylko jedna kopia w pamięci dla zmiennej statycznej
- Wszystkie składowe klasowe należą do klasy nie do instancji
- Metody statyczne nie mają dostępu do zmiennych niestatycznych
- Używamy operatora "." aby mieć dostęp do składowych statycznych, należy pamiętać że kompilator zamieni referencje nazwę klasy np.
cn.doStuff()
stanie sięClassName.doStuff()
- metody statyczne nie mogą być nadpisane ale mogą być przedefiniowane
Coupling and Cohesion
Kohezja (cohesion) - Klasy, które posiadają metody do różnych zadań, np odczyt/zapis do pliku + obróbka pliku + korekta błędów w tekście, to klasy o niskim współczynniku kohezji (robią wiele rzeczy). Kohezja, to inaczej specjalizacja klasy, a klasa o najwyższym współczynniku kohezji, to ta, która ma tylko jedną konkretną funkcję. Należy tworzyć klasy bardziej wyspecjalizowane, czyli np. dzieląc klasę na inne klasy. Wtedy uzyskujemy kilka klas ale bardziej wyspecjalizowanych.
Coupling - to luźne wiązania klas.
- Coupling odnosi się do stopnia, w którym jedna klasa wie lub korzysta z składowych innej klasy
- Luźne powiązania są pożądanym stanem klasy, oznacza to że klasa jest dobrze hermetyzowana.
- Mocne powiązania natomiast są nie pożądane i lamią zasady luźnego wiązania
- kohezja odnosi się do stopnia w którym pojedyncza klasa, ma dobrze zdefiniowane role i odpowiedzialności
- Wysoki stopień kohezji jest pożądanym stanem klasy, której składowe klasowe wspierają pojedyncze dobrze skupione role i odpowiedzialności
- Niska kohezja jest niepożądanym stanem klasy, i świadczy o tym, że składowe klasowe wspierają wiele zadań.
Kilka przykładów w kodzie aby sobie utrwalić zasady
- // wywołanie przeciążonego konstruktora poprzez
- // inny konstruktor
- class A {
- A () {
- this("foo");
- }
- A (String s) {
- this();
- }
- }
- // może wywołać błąd przepełnienia stosu
- // java.lang.StackOverflowError
- // -----------------------------------------------------------------
- // błędne zdefiniowanie konstruktora podklasy
- class Animal {
- Animal (String name) { }
- }
- class Horse extends Animal {
- Horse () {
- super (); // problem
- }
- }
- // brak takiego konstruktora w nadklasie
- // covariant return nadpisujemy zwracany typ
- class A {
- A doStuff (int a) {
- return new A();
- }
- }
- class B extends A {
- B doStuff(int b) {
- return new B();
- }
- }
- // dozwolone od java 1.5
No ina koniec mały test sprawdzający naszą wiedzę z tego co wyżej napisano ;)
Jeżeli odpowiedz się nie mieści w aplikacji, zatrzymaj się na chwilkę i zostanie wyświetlona ci cała odpowiedz.
SCJP 6 exam

Brak komentarzy:
Prześlij komentarz