Classe astratta in Java


274

Che cos'è una "classe astratta" in Java?


35
+1 Questa domanda è così semplice e fondamentale, è un classico per SO. Sono sorpreso che non sia stato chiesto qui prima.
Yuval,

6
-1 per il commento di Clemente (se potessi); lmgtfy non è una risposta utile. Per quanto riguarda il motivo, leggi ad esempio questo meta.stackexchange.com/questions/5280/embrace-the-non-googlers
Jonik

26
@tuergeist. È irrilevante se è facile per Google, purché non sia mai stato chiesto su SO prima. Inoltre, chi dice che le domande per principianti sui linguaggi di programmazione non appartengono a SO?
Jonik,

12
Una cosa che mi piace di SO è che otterresti una risposta che è condensata, ben messa e al punto senza nessuna delle solite BS trovate sul resto del web ... Beh, qualcosa del genere comunque. +1 per la domanda!
Anders Hansson,

1
Quindi non si suppone che abbia solo la coda lunga! J&J ne parla addirittura del podcast 56 ...
kwutchak,

Risposte:


342

Una classe astratta è una classe che non può essere istanziata. Una classe astratta viene utilizzata creando una sottoclasse ereditaria che può essere istanziata. Una classe astratta fa alcune cose per la sottoclasse ereditaria:

  1. Definire metodi che possono essere utilizzati dalla sottoclasse ereditaria.
  2. Definire metodi astratti che la sottoclasse ereditaria deve implementare.
  3. Fornire un'interfaccia comune che consenta di scambiare la sottoclasse con tutte le altre sottoclassi.

Ecco un esempio:

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

Si noti che "abstractMethod ()" non ha alcun metodo body. Per questo motivo, non è possibile effettuare le seguenti operazioni:

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

Non esiste un metodo che attui abstractMethod()! Quindi non c'è modo per la JVM di sapere cosa dovrebbe fare quando ottiene qualcosa di simile new ImplementingClass().abstractMethod().

Ecco un corretto ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

Si noti che non è necessario definire implementedMethod()o finalMethod(). Sono già stati definiti da AbstractClass.

Ecco un altro corretto ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

In questo caso, hai ignorato implementedMethod().

Tuttavia, a causa della finalparola chiave, non è possibile quanto segue.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

Non puoi farlo perché l'implementazione di finalMethod()in AbstractClassè contrassegnata come l'implementazione finale di finalMethod(): nessun'altra implementazione sarà consentita, mai.

Ora puoi anche implementare una classe astratta due volte:

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

Ora da qualche parte potresti scrivere un altro metodo.

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

Si noti che anche se abbiamo dichiarato bun AbstractClasstipo, viene visualizzato "Overriden!". Questo perché l'oggetto che abbiamo istanziato era in realtà un ImplementingClass, il cui implementedMethod()ovviamente è ignorato. (Potresti aver visto questo indicato come polimorfismo.)

Se desideriamo accedere a un membro specifico di una particolare sottoclasse, dobbiamo prima eseguire il cast di quella sottoclasse:

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

Infine, non puoi fare quanto segue:

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

È possibile estendere una sola classe alla volta. Se è necessario estendere più classi, devono essere interfacce. Puoi farlo:

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

Ecco un'interfaccia di esempio:

interface InterfaceA
{
    void interfaceMethod();
}

Questo è fondamentalmente lo stesso di:

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

L'unica differenza è che il secondo modo non fa sapere al compilatore che in realtà è un'interfaccia. Questo può essere utile se vuoi che le persone implementino solo la tua interfaccia e nessun altro. Tuttavia, come regola generale per principianti, se la tua classe astratta ha solo metodi astratti, probabilmente dovresti renderla un'interfaccia.

Quanto segue è illegale:

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

Non è possibile implementare metodi in un'interfaccia. Ciò significa che se si implementano due interfacce diverse, i diversi metodi in quelle interfacce non possono scontrarsi. Poiché tutti i metodi in un'interfaccia sono astratti, è necessario implementare il metodo e poiché il metodo è l'unica implementazione nella struttura ereditaria, il compilatore sa che deve utilizzare il metodo.


5
@Imagist -1 per una descrizione errata dell'istruzione c.implementedMethod (); // stampa "ImplementMethod ()", stampa "Overriden!" sempre
Sachin Kumar il

2
@Sachin Ho sprecato mezz'ora per capire perché avrebbe stampato "ImplementMethod ()" e poi ho visto il tuo commento. Qualcosa è cambiato con Java o altri hanno semplicemente trascurato l'errore?
Rounak,

@SachinKumar A causa della mancanza di risposta dell'autore, mi sono impegnato a correggere questo errore. CMIIW.
Mateen Ulhaq,

@SachinKumar Sono un po 'in ritardo al gioco qui, ma diresti che una buona analogia sarebbe una dichiarazione di metodo (ma nessuna implementazione) in un file di intestazione C ++?
Schwaitz,

5
@SachinKumar perché dovrebbe c.implementedMethod()stampare "Overriden!"? SecondImplementingClassnon sostituisce implementedMethod().
John Red

75

Una classe Java diventa astratta nelle seguenti condizioni:

1. Almeno uno dei metodi è contrassegnato come astratto:

public abstract void myMethod()

In tal caso il compilatore ti obbliga a contrassegnare l'intera classe come astratta.

2. La classe è contrassegnata come astratta:

abstract class MyClass

Come già detto: se hai un metodo astratto, il compilatore ti costringe a contrassegnare l'intera classe come astratta. Ma anche se non hai alcun metodo astratto, puoi comunque contrassegnare la classe come astratta.

Uso comune:

Un uso comune di classi astratte è quello di fornire una struttura simile a quella di un'interfaccia. A differenza di un'interfaccia, può già fornire funzionalità, ovvero alcune parti della classe sono implementate e alcune parti sono appena delineate con una dichiarazione del metodo. ("astratto")

Non è possibile creare un'istanza di una classe astratta, ma è possibile creare una classe concreta basata su una classe astratta, che può quindi essere istanziata. Per fare ciò devi ereditare dalla classe astratta e sovrascrivere i metodi astratti, cioè implementarli.


1
Nitpick: la seconda 'condizione' è ridondante, poiché puoi dichiarare un metodo astratto solo in una classe dichiarata esplicitamente come astratta.
Stephen C,

2
D'accordo, il consiglio non è proprio corretto, o ben scritto, è semplicemente formattato bene.
Noon Silk,

Ma anche il tuo consiglio "di rendere concreta una classe" è scritto in modo sbagliato. Non rendi concreta una classe, o è o non è, a seconda che sia astratta o meno.
Noon Silk,

1
Questo è semplicemente sbagliato. Una classe astratta non deve avere alcun metodo astratto. Puoi creare una classe astratta senza metodi o solo con metodi concreti.
Jorn,

1
10 anni di ritardo al gioco, ma questa è la risposta più precisa. @Jorn sei confuso con la risposta penso. Sono sicuro che è implicito che la abstractparola chiave è tutto ciò che è necessario affinché una classe sia astratta. Ma una classe concreta non può contenere un abstract metodo . Pertanto, se la tua classe ha un abstractmetodo, deve essere dichiarata come abstractclasse al compilatore.
Rakib,

24

Una classe dichiarata utilizzando la parola chiave astratta è nota come abstract class. L'astrazione è un processo per nascondere i dettagli di implementazione dei dati e mostrare all'utente solo funzionalità. L'astrazione ti consente di concentrarti su ciò che fa l'oggetto anziché su come lo fa.

Principali cose di classe astratta

  • Una classe astratta può contenere o meno metodi astratti. Possono esserci metodi non astratti.

    Un metodo astratto è un metodo dichiarato senza implementazione (senza parentesi graffe e seguito da un punto e virgola), come questo:

    es: abstract void moveTo(double deltaX, double deltaY);

  • Se una classe ha almeno un metodo astratto, quella classe deve essere astratta

  • Le classi astratte non possono essere istanziate (non è consentito creare oggetti di classe astratta)

  • Per usare una classe astratta, devi ereditarla da un'altra classe. Fornire implementazioni a tutti i metodi astratti in esso.

  • Se erediti una classe astratta, devi fornire implementazioni a tutti i metodi astratti in essa contenuti.

Dichiara classe astratta La specifica della abstractparola chiave prima della classe durante la dichiarazione la rende astratta. Dai un'occhiata al codice qui sotto:

abstract class AbstractDemo{ }

Dichiara metodo astratto La specifica della abstractparola chiave prima del metodo durante la dichiarazione la rende astratta. Dai un'occhiata al codice qui sotto,

abstract void moveTo();//no body

Perché abbiamo bisogno di astrarre le classi

In un'applicazione di disegno orientata agli oggetti, puoi disegnare cerchi, rettangoli, linee, curve di Bezier e molti altri oggetti grafici. Tutti questi oggetti hanno determinati stati (ad es.: Posizione, orientamento, colore della linea, colore di riempimento) e comportamenti (ad es.: Spostare, ruotare, ridimensionare, disegnare) in comune. Alcuni di questi stati e comportamenti sono gli stessi per tutti gli oggetti grafici (ad esempio: colore di riempimento, posizione e spostamento). Altri richiedono un'implementazione diversa (ad esempio: ridimensionare o disegnare). Tutti gli oggetti grafici devono essere in grado di disegnare o ridimensionare se stessi, differiscono solo nel modo in cui lo fanno.

Questa è una situazione perfetta per una superclasse astratta. È possibile sfruttare le somiglianze e dichiarare che tutti gli oggetti grafici ereditano dallo stesso oggetto padre astratto (per GraphicObjectesempio:) come mostrato nella figura seguente. inserisci qui la descrizione dell'immagine

Innanzitutto, si dichiara una classe astratta GraphicObject, per fornire variabili e metodi membri che sono interamente condivisi da tutte le sottoclassi, come la posizione corrente e il metodo moveTo. GraphicObjectha anche dichiarato metodi astratti, come disegnare o ridimensionare, che devono essere implementati da tutte le sottoclassi ma devono essere implementati in modi diversi. La GraphicObjectclasse può assomigliare a questa:

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

Uso del metodo astratto in sottoclassi Ogni sottoclasse non astratta di GraphicObject, come Circlee Rectangle, deve fornire implementazioni per i metodi drawe resize.

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

All'interno del mainmetodo è possibile chiamare tutti i metodi in questo modo:

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

Modi per raggiungere l'astrazione in Java

Esistono due modi per ottenere l'astrazione in Java

  • Classe astratta (da 0 a 100%)
  • Interfaccia (100%)

Classe astratta con costruttori, membri di dati, metodi, ecc

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

Produzione:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

Ricorda due regole:

  • Se la classe ha pochi metodi astratti e pochi metodi concreti, dichiarala come abstractclasse.

  • Se la classe ha solo metodi astratti, dichiarala come interface.

Riferimenti:


Perché l'ordine dei parametri xey in moveTo differisce nell'esempio sopra, nell'esempio sotto e l'output dell'esempio sotto? Se stiamo cercando di illustrare l'importanza di concetti come interfacce e classi astratte, non dovremmo usare le stesse firme di funzione delle interfacce o delle classi astratte che stiamo implementando o estendendo in modo coerente?
Jonathan Rys,

le due regole lo danno via
LiNKeR

4

È una classe che non può essere istanziata e forza l'implementazione di classi per, possibilmente, implementare metodi astratti che delinea.


3

In parole semplici, puoi pensare a una classe astratta come a un'interfaccia con un po 'più di funzionalità.

Non è possibile creare un'istanza di un'interfaccia, che vale anche per una classe astratta.

Sulla tua interfaccia puoi semplicemente definire le intestazioni del metodo e TUTTI gli implementatori sono costretti a implementarle tutte . Su una classe astratta puoi anche definire le intestazioni del tuo metodo ma qui, con la differenza dell'interfaccia, puoi anche definire il corpo (di solito un'implementazione predefinita) del metodo. Inoltre, quando altre classi estendono (nota, non implementano e quindi puoi avere solo una classe astratta per classe figlio) la tua classe astratta, non sono costretti a implementare tutti i tuoi metodi della tua classe astratta, a meno che tu non abbia specificato un metodo astratto ( in tal caso funziona come per le interfacce, non è possibile definire il corpo del metodo).

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

Altrimenti per i normali metodi di una classe astratta, gli "ereditari" possono semplicemente usare il comportamento predefinito o sovrascriverlo, come al solito.

Esempio:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}

Questa risposta non è utile se l'OP non sa cosa sia un'interfaccia. Poiché le classi e le interfacce astratte sono correlate, è altamente improbabile che l'OP ne conosca una senza conoscere l'altra.
Imagist

Ma potrebbe essere. Può darsi che sappia solo che cos'è un'interfaccia e come funziona, e poi incontra classi astratte e si chiede perché uno dovrebbe averne bisogno. Non potrebbe essere?
Juri,

3

Dalla documentazione di Oracle

Metodi e classi astratti:

Una classe astratta è una classe dichiarata astratta, che può o meno includere metodi astratti

Le classi astratte non possono essere istanziate, ma possono essere sottoclassate

Un metodo astratto è un metodo dichiarato senza implementazione (senza parentesi graffe e seguito da un punto e virgola), in questo modo:

abstract void moveTo(double deltaX, double deltaY);

Se una classe include metodi astratti, la classe stessa deve essere dichiarata astratta, come in:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

Quando una classe astratta viene sottoclassata, la sottoclasse di solito fornisce implementazioni per tutti i metodi astratti nella sua classe genitore. Tuttavia, in caso contrario, anche la sottoclasse deve essere dichiarata astratta .

Poiché abstract classese interfacessono correlati, dai un'occhiata alle domande SE seguenti:

Qual è la differenza tra un'interfaccia e una classe astratta?

Come avrei dovuto spiegare la differenza tra un'interfaccia e una classe astratta?


3

Ottieni le tue risposte qui:

Classe astratta vs interfaccia in Java

Una classe astratta può avere un metodo finale?

A proposito, queste sono le domande che hai posto di recente. Pensa a una nuova domanda per costruire la reputazione ...

Modificare:

Appena realizzato, che i poster di questo e le domande di riferimento hanno lo stesso nome o almeno simile, ma l'ID utente è sempre diverso. Quindi, c'è anche un problema tecnico, che keyur ha problemi ad accedere di nuovo e a trovare le risposte alle sue domande o questa è una sorta di gioco per intrattenere la comunità SO;)


Ed è per questo che ho controllato 'wiki comunità' - non si dovrebbe aumentare la reputazione reagendo a queste domande;)
Andreas Dolk,

1

Piccola aggiunta a tutti questi post.

A volte potresti voler dichiarare una classe e tuttavia non sapere come definire tutti i metodi che appartengono a quella classe. Ad esempio, potresti voler dichiarare una classe chiamata Writer e includere in essa un metodo membro chiamato write () . Tuttavia, non sai come scrivere il codice () perché è diverso per ogni tipo di dispositivo Writer. Naturalmente, prevedi di gestirlo derivando una sottoclasse di Writer, come Stampante, Disco, Rete e Console.


1

Una classe astratta non può essere istanziata direttamente, ma deve essere derivata per essere utilizzabile. Una classe DEVE essere astratta se contiene metodi astratti: direttamente

abstract class Foo {
    abstract void someMethod();
}

o indirettamente

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

Tuttavia, una classe può essere astratta senza contenere metodi astratti. È un modo per prevenire l'istanza diretta, ad es

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

Quest'ultimo stile di classi astratte può essere usato per creare classi "simili a interfacce". A differenza delle interfacce, una classe astratta può contenere metodi non astratti e variabili di istanza. Puoi usarlo per fornire alcune funzionalità di base per estendere le classi.

Un altro modello frequente è l'implementazione della funzionalità principale nella classe astratta e la definizione di parte dell'algoritmo in un metodo astratto che deve essere implementato da una classe estesa. Stupido esempio:

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}

1

Soluzione - classe base (astratto)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}

1
prova a formattare tutto il codice come codice e aggiungi qualche spiegazione, in questo momento difficilmente può essere considerata una risposta.
NomeN,

3
fino a quando ea meno che tu non abbia fornito una spiegazione del tuo codice. Saresti considerato un creatore di cattive risposte. Quindi, per favore, dai una spiegazione qui
devsda,

0

Una classe astratta è una classe dichiarata astratta - può o meno includere metodi astratti. Le classi astratte non possono essere istanziate, ma possono essere sottoclassate.

In altre parole, una classe dichiarata con una parola chiave astratta, è conosciuta come classe astratta in java. Può avere metodi astratti (metodo senza corpo) e metodi non astratti (metodo con corpo).

Nota importante: - Le classi astratte non possono essere utilizzate per creare un'istanza di oggetti, ma possono essere utilizzate per creare riferimenti a oggetti, poiché l'approccio di Java al polimorfismo di runtime viene implementato mediante l'uso di riferimenti di superclasse. Pertanto, deve essere possibile creare un riferimento a una classe astratta in modo che possa essere utilizzato per puntare a un oggetto di sottoclasse. Vedrai questa funzione nell'esempio seguente

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 

0

Una classe astratta è una classe che non è completamente implementata ma fornisce una sorta di progetto per le sottoclassi. Può essere parzialmente implementato in quanto contiene metodi concreti completamente definiti, ma può anche contenere metodi astratti. Questi sono metodi con una firma ma nessun corpo del metodo. Qualsiasi sottoclasse deve definire un corpo per ciascun metodo astratto, altrimenti deve essere dichiarato astratto. Poiché le classi astratte non possono essere istanziate, per essere utilizzate devono essere estese di almeno una sottoclasse. Pensa alla classe astratta come alla classe generica e le sottoclassi sono lì per riempire le informazioni mancanti.


0

Classe che può avere metodi sia concreti che non concreti, ovvero con e senza corpo.

  1. I metodi senza implementazione devono contenere parole chiave "astratte".
  2. La classe astratta non può essere istanziata.

-1

Non fa nulla, basta fornire un modello comune che verrà condiviso per la sua sottoclasse

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.