CodeGym /Java Blog /Random-IT /Esempi specifici di classi astratte in Java
John Squirrels
Livello 41
San Francisco

Esempi specifici di classi astratte in Java

Pubblicato nel gruppo Random-IT
CIAO! Nelle lezioni precedenti, abbiamo incontrato le interfacce e capito a cosa servono. L'argomento di oggi farà eco a quello precedente. Parliamo di classi astratte in Java. Esempi specifici di classi astratte in Java - 1

Perché le classi sono chiamate "astratte"

Probabilmente ti ricordi cos'è l'"astrazione": l'abbiamo già esaminata. :) Se te ne sei dimenticato, non temere. Ricorda: è un principio di OOP che dice quando si progettano classi e si creano oggetti, dovremmo identificare solo le proprietà principali dell'entità e scartare quelle secondarie. Ad esempio, se stiamo progettando una SchoolTeacherclasse, difficilmente abbiamo bisogno di una proprietà ' height '. In effetti, questa proprietà è irrilevante per un insegnante. Ma se stiamo creando una BasketballPlayerclasse, allora la crescita sarebbe una caratteristica importante. Quindi ascolta. Una classe astrattaè tanto astratto quanto viene - un "vuoto" incompiuto per un gruppo di classi future. Il vuoto non può essere utilizzato così com'è. È troppo "crudo". Ma descrive alcuni stati e comportamenti generali che saranno posseduti dalle classi future che erediteranno la classe astratta.

Esempi di classi Java astratte

Considera un semplice esempio con le auto:

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, non è niente di speciale :) Perché ne avremmo bisogno? Prima di tutto, descrive la nostra entità richiesta, un'auto, nel modo più astratto possibile. C'è un motivo per cui usiamo la parola abstract . Nel mondo reale non esistono "auto astratte". Ci sono camion, auto da corsa, berline, coupé e SUV. La nostra classe astratta è semplicemente un "progetto" che useremo in seguito per creare classi di auto.

public class Sedan extends Car {

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

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

}
Questo è molto simile a quello di cui abbiamo parlato nelle lezioni sull'ereditarietà. Ma in quelle lezioni avevamo una lezione di auto e i suoi metodi non erano astratti. Ma quella soluzione ha una serie di inconvenienti che vengono risolti nelle classi astratte. Innanzitutto, non puoi 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!
   }
}
I creatori di Java hanno progettato specificamente questa "caratteristica". Ancora una volta, come promemoria: una classe astratta è solo un progetto per future classi "normali" . Non hai bisogno di copie del progetto, giusto? E non crei istanze di una classe astratta :) Ma se la Carclasse non fosse astratta, potremmo facilmente crearne istanze:

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 fine. A car is created.
   }
}
Ora il nostro programma ha una specie di macchina incomprensibile: non è un camion, non un'auto da corsa, non una berlina, e non è del tutto chiaro cosa sia. Questa è proprio la "macchina astratta" che non esiste in natura. Possiamo fornire lo stesso esempio usando gli animali. Immagina se le Animalclassi ( animali astratti ). Non è chiaro che tipo di animale sia, a quale famiglia appartenga e quali caratteristiche abbia. Sarebbe strano vederlo nel tuo programma. Non ci sono "animali astratti" in natura. Solo cani, gatti, volpi, talpe, ecc. Le classi astratte ci liberano da oggetti astratti. Ci danno lo stato e il comportamento di base. Ad esempio, tutte le auto dovrebbero avere un modello , un colore e una velocità massima e dovresti essere in grado di applicare ilgas e freno . Questo è tutto. Questo è un piano astratto generale. Quindi progetti le classi di cui hai bisogno. Nota: anche due metodi nella classe abstract sono designati come abstract e non hanno alcuna implementazione. Il motivo è lo stesso: le classi astratte non creano un comportamento predefinito per le auto astratte. Indicano solo ciò che ogni macchina dovrebbe essere in grado di fare. Tuttavia, se hai bisogno di un comportamento predefinito, puoi implementare 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("Gas!");
   }

   public abstract void brake();

   // Getters and setters
}


public class Sedan extends Car {

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

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Output della console: "Gas!" Come puoi vedere, abbiamo implementato il primo metodo nella classe astratta e non il secondo. Di conseguenza, il Sedancomportamento della nostra classe è diviso in due parti: se chiami il gas()metodo, la chiamata "sale" fino alla Carclasse genitore astratta, ma abbiamo ignorato il brake()metodo nella Sedanclasse. Questo risulta essere molto conveniente e flessibile. Ma ora la nostra classe non è così astratta ? Dopotutto, metà dei suoi metodi sono implementati. Questo è in realtà una caratteristica molto importante: una classe è astratta se almeno uno dei suoi metodi è astratto. Uno dei due metodi, o almeno uno dei mille metodi: non fa differenza. Possiamo persino implementare tutti i metodi e non lasciarne nessuno astratto. Quindi sarebbe una classe astratta senza metodi astratti. In linea di principio, questo è possibile e il compilatore non genererà errori, ma è meglio evitarlo: la parola abstract perde il suo significato e i tuoi colleghi programmatori saranno molto sorpresi :/ Allo stesso tempo, se un metodo è contrassegnato con la parola abstract, ogni classe figlia deve implementarla o dichiararla come astratta. In caso contrario, il compilatore genererà un errore. Ovviamente ogni classe può ereditare solo una classe astratta, quindi in termini di ereditarietà non c'è differenza tra classi astratte e ordinarie. Non importa se ereditiamo una classe astratta o ordinaria, ci può essere solo una classe genitore.

Perché Java non ha ereditarietà multipla delle classi

Abbiamo già detto che Java non ha ereditarietà multipla, ma non abbiamo davvero esplorato il motivo. Proviamo a farlo ora. Il fatto è che se Java avesse ereditarietà multipla, le classi figlie non sarebbero in grado di decidere quale comportamento specifico dovrebbero scegliere. Supponiamo di avere due classi — Toastere NuclearBomb:

public class Toaster {


 public void on() {

       System.out.println("The toaster is on. Toast is being prepared!");
   }

   public void off() {

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


public class NuclearBomb {

   public void on() {

       System.out.println("Boom!");
   }
}
Come puoi vedere, entrambi hanno un on()metodo. Per un tostapane, inizia a tostare. Per una bomba nucleare, fa esplodere. Oops: / Ora immagina di aver deciso (non chiedermi perché!) di creare una via di mezzo. E così hai una MysteriousDeviceclasse! Questo codice, ovviamente, non funziona e lo forniamo solo come esempio "ma potrebbe essere":

public class MysteriousDevice extends Toaster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // So what should happen here? Do we get toast or a nuclear apocalypse?
   }
}
Diamo un'occhiata a quello che abbiamo. Il misterioso dispositivo eredita contemporaneamente Toaster e NuclearBomb. Entrambi hanno on()metodi. Di conseguenza, se chiamiamo il on()metodo, non è chiaro quale debba essere invocato sull'oggetto MysteriousDevice. Non c'è modo che l'oggetto possa mai saperlo. E per finire: NuclearBomb non ha un off()metodo, quindi se non abbiamo indovinato, sarà impossibile disabilitare il dispositivo. Esempi specifici di classi astratte in Java - 2È proprio a causa di questa 'confusione', in cui l'oggetto non sa quale comportamento esibire, che i creatori di Java hanno abbandonato l'ereditarietà multipla. Tuttavia, ricorderai che le classi Java possono implementare più interfacce. A proposito, nei tuoi studi hai già incontrato almeno una classe astratta!

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
È il tuo vecchio amico, la Calendarclasse. È astratto e ha diversi figli. Uno di loro è GregorianCalendar. L'hai già usato nelle lezioni sulle date. :) Tutto sembra abbastanza chiaro. C'è solo una domanda: qual è comunque la differenza fondamentale tra classi astratte e interfacce? Perché hanno aggiunto entrambi a Java invece di limitare il linguaggio a uno solo? Dopotutto, sarebbe stato del tutto adeguato. Ne parleremo nella prossima lezione ! Fino ad allora :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION