Vantaggio di dichiarare e inizializzare tipi di oggetti diversi?

2

Sto imparando come usare java per programmare e sto solo imparando a conoscere le classi astratte e come sono utili. Diciamo che ho una classe che estende un'altra classe astratta, che ha 2 metodi, uno dei quali è astratto. La mia altra classe non astratta ha 4 metodi, due dei quali sono gli stessi della classe astratta e definisce anche il metodo astratto. Quando inizializzo il mio secondo oggetto, il mio corso mi dice di usare: (abstract class) foo = new (nonabstract class)(); La mia domanda, è che l'uso di questo codice ti impedisce di usare i metodi che sono stati aggiunti nella classe non astratta e, di conseguenza, qual è il vantaggio di usare quel codice oltre (nonabstract class) foo = new (nonabstract class) , che consente di utilizzare entrambi i metodi nella classe astratta e i metodi aggiunti nella classe non astratta. Grazie per l'aiuto in anticipo.

    
posta quixotrykd 27.03.2015 - 05:14
fonte

1 risposta

3

I contenitori (elenchi, ecc.) che sono definiti per contenere oggetti di una determinata classe base possono contenere qualsiasi oggetto esteso da quella classe base. Ci sono molte situazioni nella progettazione del software in cui questa funzionalità è utile. La classe base può specificare che alcuni comportamenti saranno richiesti, ma potremmo non sapere esattamente come dovrebbero essere implementati perché sarà diverso a seconda delle caratteristiche delle nuove classi che si estendono da esso.

Per prendere a prestito da un esempio molto comune di polimorfismo, in un programma di disegno, dì che hai tre classi:

abstract class Shape {
    private Point position; 

    public Point getPosition(){ return position; }

    // Every Shape has an area, but we don't know
    // how to calculate it until we know what kind
    // of Shape it is. So this is defined, but it's
    // abstract.
    public abstract float getArea(); 
}

class Rectangle extends Shape {
    private float length;
    private float width;

    public float getArea(){ return length * width; }

    public float getLength(){ return length; }
    public float getWidth(){ return width; }
}

class Circle extends Shape {
    private float radius;

    public float getArea(){ return Math.PI * radius * radius; }

    public float getRadius(){ return radius; }
}

Ora, nel tuo codice, potresti avere un contenitore che contiene% oggettiShape. Potrebbero essere Circle o Rectangle oggetti. Definendo il tuo contenitore in termini di classe base, puoi ora tenere entrambe le sottoclassi in modo sicuro e puoi chiamare getPosition () e getArea () su qualsiasi cosa nel contenitore.

List<Shape> shapes = new ArrayList<Shape>();
shapes.add(new Rectangle(5,10));
shapes.add(new Circle(5));

for (Shape s : shapes){
    s.getPosition();  // <-- this is OK
    s.getArea();      // <-- this is OK

    s.getRadius(); // <-- This produces a compiler error
    s.getWidth();  // <-- This produces a compiler error
}

Chiamare getRadius () o getWidth () su Shape causa un errore del compilatore, poiché Shape non fornisce tali metodi. Dovresti saperne di più sull'oggetto e lanciare l'oggetto sul tipo corretto prima di chiamare i metodi più specifici.

if (s instanceof Rectangle){
    ((Rectangle)s).getWidth();
}

if (s instanceof Circle){
    ((Circle)s).getRadius();
}

Si noti che questo esempio utilizza in modo specifico una classe base astratta con ereditarietà, poiché esiste qualcosa che la classe base può effettivamente implementare (la posizione). Nel caso in cui la classe base sia puramente astratta e non fornisca alcuna implementazione concreta da ereditare dalle sottoclassi, probabilmente si definirà un'interfaccia, piuttosto che una classe. E le sottoclassi implementerebbero le interfacce.

    
risposta data 27.03.2015 - 06:18
fonte

Leggi altre domande sui tag