Tworzymy klasę, która nic nie rozszerza (poza Object) gdy
nie przechodzi ona testu IS-A dla jakiegokolwiek innego typu(?).
Tworzymy podklasę (rozszerzamy klasę nadrzędną) wtedy, gdy
musimy utworzyć bardziej wyspecjalizowaną wersję klasy oraz
potrzebujemy zastąpić lub dodać nowe zachowania (metody).
Korzystamy z klasy abstrakcyjnej, gdy chcemy zdefiniować
wzorzec dla grupy podklas i mamy przynajmniej trochę kodu
implementacji, który wszystkie podklasy mogłyby wykorzystać.
Robimy daną klasę abstrakcyjną, gdy chcemy zagwarantować, że
nikt nie utworzy obiektów tego typu.
Korzystamy z interfejsu, gdy chcemy zdefiniować rolę, jaką
inne klasy mogą spełniać, niezależnie od ich pozycji w
drzewie dziedziczenia.
=== Bullet Points ===
* Gdy nie chcemy by można było utworzyć obiekt danej klasy, oznaczamy ją słowem kluczowym "abstract".
* Klasa abstrakcyjna może posiadać abstrakcyjne i nieabstrakcyjne metody.
* Jeśli klasa ma przynajmniej jedną metodę abstrakcyjną, musi być oznaczona jako abstrakcyjna.
* Metoda abstrakcyjna nie ma ciała, jej deklaracja kończy się średnikiem (brak nawiasów klamrowych).
* Wszystkie metody abstrakcyjne muszą zostać zaimplementowane w pierwszej konkretnej podklasie w drzewie dziedziczenia.
* Każda klasa w Javie jest podklasą klasy Object (java.lang.Object), czy to bezpośrednio czy pośrednio.
* Metody mogą być deklarowane z argumentami i/lub zwracanymi typami Object.
* Zmienna referencyjna typu Object może być tylko wykorzystana do przywołania metod zdefiniowanych w klasie Object, niezależnie od typu obiektu, którego jest referencją.
* Zmienna referencyjna typu Object nie może być przypisana do jakiegokolwiek innego typu bez rzutowania. Rzutowanie może być wykorzystane do przypisania zmiennej referencyjnej jednego typu do zmiennej referencyjnej podtypu, ale podczas działania programu, rzutowanie zakończy się błędem, jeśli obiekt na stercie (heap) nie jest kompatybilny z rzutowanym. Przykład:
Dog d = (Dog) x.getObject(aDog);
* Obiekty wychodzą z ArrayList