Ciao! Nelle lezioni precedenti abbiamo già affrontato brevemente più volte il concetto di ereditarietà. Oggi toccheremo anche questo argomento, ma anche non troppo in profondità. Ci sarà una lezione dettagliata su questo argomento più tardi, ma oggi vedremo solo esempi pratici e faremo conoscenza con un operatore interessante in Java.
Eredità Java
Quindi, cos’è esattamente l’ereditarietà? L'ereditarietà è un meccanismo nella programmazione, incluso Java, che consente di descrivere una nuova classe basata su una esistente. La classe discendente ottiene quindi l'accesso ai campi e ai metodi della classe genitore. Perché potrebbe essere necessario? Bene, ad esempio, immagina di dover creare diverse classi di auto nel programma: camion, corsa, berlina, pick-up, ecc. Anche senza iniziare a scrivere codice, sai per certo che queste classi hanno molto in comune: tutte le auto hanno il nome del modello, l'anno di produzione, la cilindrata del motore, la velocità massima, ecc. (per non parlare del fatto che hanno tutti ruote e altre parti). In una situazione del genere, puoi:- Crea questi campi in ciascuna classe e aggiungili alle nuove classi di auto quando vengono create
- Spostando i campi comuni a tutte le macchine nella classe genitore
Car
, tutte le classi di tipi specifici di macchine erediteranno dall'usoCar
della parola 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);
}
}
Come minimo, abbiamo evitato inutili duplicazioni del codice, e questo è qualcosa a cui dovremmo sempre aspirare quando scriviamo programmi. Inoltre, abbiamo una struttura di classi semplice e comprensibile: i campi comuni a tutte le macchine sono collocati in un'unica classe. Se, ad esempio, i camion hanno dei campi specifici che le altre auto non hanno, possono essere dichiarati nel file Truck
. Lo stesso vale per i metodi. Tutte le auto hanno alcuni comportamenti comuni che possono essere descritti: avviare l'auto, accelerare/frenare, ecc. Questi metodi generali possono essere inseriti in una classe generale Car
e il comportamento specifico di ciascun tipo specifico può essere descritto in classi discendenti.
public class Car {
public void gas() {
//...gas
}
public void brake() {
//...brake
}
}
public class F1Car extends Car {
public void pitStop() {
//...only racing cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Abbiamo spostato i metodi comuni a tutte le auto nella classe Car
. Ma nella classe successiva F1Car
, che descrive le auto da corsa di Formula 1, ci sono i pit stop (soste per la manutenzione urgente dell'auto), che vengono effettuati solo nelle corse e si distinguono per un comportamento specifico.
Operatore di istanza Java
Per verificare se un oggetto viene creato in base a una classe, esiste un operatore speciale in Java -instanceof
. Restituisce il valore true
se il test era vero o false
se il risultato era falso. Vediamo come funziona usando come esempio le nostre classi di auto:
public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}
Risultato: true Test utilizzando l'operatore instanceof
restituito true
, poiché abbiamo un oggetto della classe Truck
e tutti i camion sono automobili. La classe Truck
è un discendente della classe Car
, pertanto tutti i camion vengono creati sulla base di un genitore comune: l'auto. Attenzione all'operatore instanceof
: è scritto senza punto, poiché è un operatore, non un metodo (“oggetto istanza di Classe”). Proviamolo diversamente:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}
Output: false La classe Car
e, di conseguenza, il suo oggetto non derivano dalla classe Truck
.Tutti i camion sono automobili, ma non tutte le auto sono camion. Gli oggetti Car
non vengono creati in base alla classe Truck
. Un altro esempio:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}
Output: True Anche qui la logica è semplice: tutte le classi in Java, comprese quelle che hai creato, provengono da una classe Object
(anche se non scrivi extends Object in esse - questo meccanismo è implicito in esse). Perché potrebbe essere utile e in quali circostanze? L'uso più comune dell'operatore instanceof
è come override del metodo equals()
. Ad esempio, ecco come viene implementato il metodo equals
nella classe 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;
}
Prima di confrontare la stringa con l'oggetto passato, il metodo verifica: l'oggetto passato è effettivamente una stringa? E solo allora inizia a confrontare le proprietà di due oggetti. Senza questo controllo, potresti passare qualsiasi oggetto che abbia campi valore e lunghezza nel metodo e confrontarlo con una stringa, il che, ovviamente, sarebbe sbagliato.
GO TO FULL VERSION