Cześć! W poprzednich wykładach już kilkakrotnie zetknęliśmy się pokrótce z pojęciem dziedziczenia. Dziś również poruszymy ten temat, ale też niezbyt głęboko. Szczegółowy wykład na ten temat będzie później, ale dzisiaj przyjrzymy się tylko praktycznym przykładom i poznamy jeden ciekawy operator w Javie.
Dziedziczenie Javy
Czym właściwie jest dziedziczenie? Dziedziczenie to mechanizm występujący w programowaniu, w tym w Javie, pozwalający na opisanie nowej klasy na podstawie już istniejącej. Klasa potomna uzyskuje wówczas dostęp do pól i metod klasy nadrzędnej. Dlaczego może to być konieczne? Cóż, na przykład, wyobraź sobie, że musisz utworzyć w programie kilka klas samochodów: ciężarówka, wyścigi, sedan, pick-up itp. Nawet nie zaczynając pisać kodu, wiesz na pewno, że te klasy mają ze sobą wiele wspólnego: wszystkie samochody mają nazwę modelu, rok produkcji, pojemność silnika, maksymalną prędkość itp. (nie wspominając o tym, że wszystkie mają koła i inne części). W takiej sytuacji możesz:- Utwórz te pola w każdej klasie i dodaj je do nowych klas samochodów, gdy zostaną utworzone
- Przenieś pola wspólne dla wszystkich maszyn do klasy nadrzędnej
Car
, a wszystkie klasy określonych typów maszyn dziedziczą poCar
użyciu słowa Extends .
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
Przynajmniej uniknęliśmy niepotrzebnego powielania kodu i do tego powinniśmy zawsze dążyć pisząc programy. Dodatkowo mamy prostą i zrozumiałą strukturę klas: pola wspólne dla wszystkich maszyn umieszczone są w jednej klasie. Jeśli na przykład ciężarówki mają pewne specyficzne pola, których nie mają inne samochody, można je zadeklarować w tej klasie Truck
. To samo tyczy się metod. Wszystkie samochody mają pewne wspólne zachowanie, które można opisać: uruchamianie samochodu, gaz/hamulec itp. Te ogólne metody można umieścić w klasie ogólnej Car
, a specyficzne zachowanie każdego konkretnego typu można opisać w klasach potomnych.
public class Car {
public void gas() {
//...gaz
}
public void brake() {
//...hamulec
}
}
public class F1Car extends Car {
public void pitStop() {
//...tylko samochody wyścigowe robią pit stopy
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Przenieśliśmy wspólne metody stosowane we wszystkich samochodach do tej klasy Car
. Natomiast w klasie następczej F1Car
, która opisuje samochody wyścigowe Formuły 1 - pit stopy (przystanki w celu pilnej konserwacji samochodu), które odbywają się wyłącznie w wyścigach i wyróżniają się specyficznym zachowaniem.
Operator instancji Java
Aby sprawdzić, czy obiekt jest tworzony na podstawie klasy, w Javie dostępny jest specjalny operator -instanceof
. Zwraca wartość true
, jeśli test był prawdziwy lub false
jeśli wynik był fałszywy. Zobaczmy jak to działa na przykładzie naszych klas samochodów:
public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}
Wynik: true Kontrola przy użyciu operatora instanceof
zwróciła true
, ponieważ mamy obiekt klasy Truck
, a wszystkie ciężarówki to samochody. Klasa Truck
jest potomkiem klasy Car
, dlatego wszystkie ciężarówki tworzone są w oparciu o wspólnego rodzica – samochód. Zwróć uwagę na operator instanceof
: jest on napisany bez kropki, ponieważ jest operatorem, a nie metodą („instancja obiektu klasy”). Spróbujmy inaczej:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}
Wynik: false Klasa Car
i odpowiednio jej obiekt nie wywodzą się z klasy Truck
. Wszystkie ciężarówki to samochody, ale nie wszystkie samochody to ciężarówki. Obiekty Car
nie są tworzone w oparciu o klasę Truck
. Jeszcze jeden przykład:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}
Wynik: True Logika tutaj jest również prosta: wszystkie klasy w Javie, łącznie z tymi, które stworzyłeś, pochodzą z klasy Object
(chociaż nie piszesz w nich rozszerzającego obiektu - ten mechanizm jest w nich ukryty). Dlaczego może się to przydać i w jakich okolicznościach? Najczęstszym zastosowaniem operatora instanceof
jest przesłonięcie metody equals()
. Oto przykładowa implementacja metody equals
w klasie String
:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
Przed porównaniem ciągu znaków z przekazanym obiektem metoda sprawdza: czy przekazany obiekt rzeczywiście jest ciągiem znaków? I dopiero wtedy zaczyna porównywać właściwości dwóch obiektów. Bez tej kontroli można by przekazać do metody dowolny obiekt posiadający pola wartości i długości i porównać go z ciągiem znaków, co oczywiście byłoby błędne.
GO TO FULL VERSION