JavaRush /Java Blog /Random-IT /Classi astratte in Java con esempi specifici

Classi astratte in Java con esempi specifici

Pubblicato nel gruppo Random-IT
Ciao! Nelle lezioni precedenti abbiamo conosciuto le interfacce e scoperto a cosa servono. L'argomento di oggi avrà qualcosa in comune con quello precedente. Parliamo di classi astratte in Java. Classi astratte in Java con esempi concreti - 1

Perché le classi sono chiamate "astratte"

Probabilmente ricordi cos'è l '"astrazione" - ne abbiamo già parlato :) Se all'improvviso te ne sei dimenticato, va bene, ricordiamolo: questo è il principio dell'OOP , secondo il quale quando si progettano classi e si creano oggetti, è necessario evidenziare solo le proprietà principali di un'entità e scartare quelle secondarie. Ad esempio, se stiamo progettando una classe SchoolTeacher- un insegnante di scuola - difficilmente avremo bisogno della caratteristica “ altezza ”. Anzi: per un insegnante questa caratteristica non è importante. Ma se creiamo una classe nel programma BasketballPlayer, un giocatore di basket, l'altezza diventerà una delle caratteristiche principali. Quindi, una classe astratta è il “vuoto” più astratto, davvero approssimativo, per un gruppo di classi future. Questa preparazione non può essere utilizzata nella sua forma finita: è troppo "grezza". Ma descrive un certo stato generale e comportamento che avranno le classi future, eredi della classe astratta.

Esempi di classi astratte Java

Diamo un'occhiata a un semplice esempio con le automobili:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
Ecco come appare la classe astratta più semplice. Come puoi vedere, niente di speciale :) A cosa potrebbe servire? Innanzitutto descrive nel modo più astratto possibile l'entità di cui abbiamo bisogno: un'auto. La parola astratto è qui per una ragione. Non esistono “solo macchine” al mondo. Ci sono camion, auto da corsa, berline, coupé, SUV. La nostra classe astratta è semplicemente un "progetto" da cui successivamente creeremo classi di auto.
public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println("The sedan accelerates!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}
Questo è molto simile a ciò di cui abbiamo parlato nelle lezioni sull'eredità. Solo lì avevamo una classe Care i suoi metodi che non erano astratti. Ma questa soluzione presenta una serie di svantaggi, che vengono corretti in classi astratte. Innanzitutto non è possibile creare un'istanza di una classe astratta:
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Questo "trucco" è stato implementato appositamente dai creatori di Java. Ancora una volta, giusto per ricordare: una classe astratta è solo un progetto per future classi "normali" . Non hai bisogno di copie del disegno, giusto? Quindi non è necessario creare istanze di una classe astratta :) E se la classe Carnon fosse astratta, potremmo facilmente creare i suoi oggetti:
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // some logic
   }

   public  void brake() {
       // some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Everything is OK, the machine has been created
   }
}
Ora nel nostro programma abbiamo una specie di macchina strana: non un camion, non un'auto da corsa, non una berlina, ma qualcosa in generale. Quella stessa “solo una macchina” che non esiste in natura. Lo stesso esempio può essere fatto con gli animali. Immagina se nel tuo programma apparissero degli oggetti Animal: " solo un animale ". Di che tipo è, a quale famiglia appartiene, quali caratteristiche ha: non è chiaro. Sarebbe strano vederlo nel programma. In natura non esistono “solo animali”. Solo cani, gatti, volpi, talpe e altri. Le classi astratte ci liberano dai “ solo oggetti ”. Ci danno uno stato e un comportamento di base. Ad esempio, tutte le auto devono avere un modello , un colore e una velocità massima , e devono anche poter dare gas e frenare . È tutto. Questo è uno schema astratto generale, quindi progetti tu stesso le classi di cui hai bisogno. Nota: anche due metodi in una classe astratta sono designati come abstract e non sono affatto implementati. Il motivo è lo stesso: le classi astratte non creano "comportamenti predefiniti" per "semplici macchine". Dicono solo che dovrebbero essere in grado di costruire tutte le auto. Tuttavia, se hai ancora bisogno del comportamento predefinito, puoi implementare i metodi in una classe astratta. Java non lo vieta:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Let's go!");
   }

   public abstract void brake();

   //getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Output della console: "Accelera!" Come puoi vedere, abbiamo implementato un metodo nella classe astratta, ma non abbiamo implementato il secondo. Di conseguenza, il comportamento della nostra classe Sedanè stato diviso in due parti: se chiami un metodo su di essa gas(), si “tirerà su” dalla classe astratta genitore Care brake()abbiamo ridefinito il metodo nella classe Sedan. Si è rivelato molto conveniente e flessibile. Ma ora la nostra classe non è più così astratta ? Dopotutto, infatti, la metà dei suoi metodi vengono implementati. Infatti – e questa è una caratteristica molto importante – una classe è astratta se almeno uno dei suoi metodi è astratto . Almeno uno dei due, almeno uno dei mille metodi, non importa. Possiamo anche implementare tutti i metodi e non lasciarne nessuno astratto. Ci sarà una classe astratta senza metodi astratti. In linea di principio questo è possibile e il compilatore non produrrà errori, ma è meglio non farlo: la parola abstract perderà il suo significato e i tuoi colleghi programmatori saranno molto sorpresi di vederlo :/ Inoltre, se un metodo è contrassegnato dalla parola abstract, ogni classe discendente deve implementare o essere dichiarata abstract. Altrimenti il ​​compilatore genererà un errore . Naturalmente, ogni classe può ereditare da una sola classe astratta, quindi in termini di ereditarietà non c'è differenza tra classi astratte e classi regolari. Non importa se ereditiamo da una classe astratta o da una normale, può esserci solo una classe genitore.

Perché non esiste l'ereditarietà di classi multiple in Java?

Abbiamo già detto che in Java non esiste l’ereditarietà multipla, ma non abbiamo ancora capito il perché. Proviamolo adesso. Il punto è che se Java avesse ereditarietà multipla, le classi figlie non sarebbero in grado di decidere quale comportamento scegliere. Diciamo che abbiamo due classi - Tostere NuclearBomb:
public class Toster {


 public void on() {

       System.out.println("The toaster is on, the toast is getting ready!");
   }

   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Взрыв!");
   }
}
Come puoi vedere, entrambi hanno un metodo on(). Nel caso di un tostapane, inizia a cuocere i toast e, nel caso di una bomba nucleare, provoca un'esplosione. Oh :/ Ora immagina di aver deciso (non so perché all'improvviso!) di creare qualcosa nel mezzo. Ed eccola qui la tua classe - MysteriousDevice! Questo codice, ovviamente, non funziona e lo presentiamo semplicemente come esempio di “come potrebbe essere”:
public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // And what should happen here? Will we get a toast, or a nuclear apocalypse?
   }
}
Vediamo cosa abbiamo ottenuto. Il misterioso dispositivo proviene sia dal tostapane che dalla bomba nucleare. Entrambi hanno un metodo on()e, di conseguenza, non è chiaro quale metodo on()dovrebbe attivarsi sull'oggetto MysteriousDevicese lo chiamiamo. L'oggetto non sarà in grado di capirlo. Bene, come ciliegina sulla torta: la bomba nucleare non ha alcun metodo off(), quindi se abbiamo indovinato, non ci sarà modo di spegnere il dispositivo. Classi astratte in Java con esempi concreti - 2 È proprio a causa di questa confusione, quando un oggetto non è chiaro quale comportamento dovrebbe scegliere, che i creatori di Java hanno abbandonato l'ereditarietà multipla. Tuttavia, tieni presente che le classi Java implementano molte interfacce. A proposito, hai già incontrato almeno una lezione astratta nei tuoi studi! Anche se forse non me ne sono accorto :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Questa è la tua vecchia classe di amici Calendar. È astratto e ha diversi eredi. Uno di essi è GregorianCalendar. L'hai già usato nelle lezioni sulle date :) Tutto sembra essere chiaro, rimane solo un punto: qual è la differenza fondamentale tra classi astratte e interfacce ? Perché li hanno aggiunti entrambi a Java e non si sono limitati a uno solo? Questo potrebbe essere sufficiente. Ne parleremo nella prossima lezione! Ci vediamo:)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION