# Introduzione su oggetti

## Riutilizzo dell'implementazione

Ci sono due modi per riutilizzare le classi esistenti, la composition (o anche detta aggregazione) e con l'ereditarietà.&#x20;

Con la *composition*, definiamo una nuova classe, che è composta di classi già esistenti. Con l'*ereditarietà*, si deriva una nuova classe basandosi  su classi già esistenti, con modifiche o esensioni.

### Aggregazione (composition)

![Aggregazione](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVm6uVhj_2LUPEn6z_w%2F-LVm8eGf71j-UERHrjm6%2FAggregazione.PNG?alt=media\&token=fe80abde-cac6-453f-9628-e34045064129)

L' aggregazione permette di costruire oggetto più complessi ad esempio un oggetto di tipo (classe) **Car** dalla composizione di oggetti di altri tipi ad esempio **Engine** o **Weel**. La relazione aggregazione è detta anche "**has-a**", es: 'La macchina ha un motore'.

### Ereditarietà e Polimorfismo

#### Ereditarietà

![UML classe padre-figlio](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVm6uVhj_2LUPEn6z_w%2F-LVm9lSmUxDtJPK0ZqFc%2FIneritance_1.PNG?alt=media\&token=10b27261-fa17-49cb-b30d-15cdcced8fc4)

Sopra grafico UML relazione superclasse/sottoclasse.

Sotto esempio di relazione tra la superclasse shape e le sottoclassi *Circle*, *Square* e *Triangle*, sottoclassi di *Shape*.

![Type hierarchy](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVm6uVhj_2LUPEn6z_w%2F-LVmARl5SvkLBL606Uy7%2FIneritance_2.PNG?alt=media\&token=434c7753-6174-4d36-a360-5d5de3239d90)

Le sottoclassi Circle, Square e Triangle ereditano i metodi *draw()*, *erase()*, *move()*,  *getColor()* e *setColor()* dalla superclasse *Shape*.

Nell'esempio sotto vediamo che la sottoclasse *Triangle*, estende la classe *Shape* in quanto aggiunge due metodi a quelli ereditati da Shape, i metodi *`FlipVertical()`* e *`FlipHorizontal()`*.

![](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVm6uVhj_2LUPEn6z_w%2F-LVmB3swGgOqhuFCkleN%2FIneritance_3.PNG?alt=media\&token=d3e4a1c6-f24b-4ee9-9e53-f909795af6ac)

Sebbene ereditarietà implica talvolta (specialmente in Java, dove la keyword per l'ereditarietà è **extends**) che to stia andando ad aggiungere nuovi metodi nella sottoclasse, questo non è necessariamente vero. Il secondo e più importante metodo per differenziare la tua nuova classe è cambiare il comportamento del metodo della classe base. Questo è comunemente dettto fare l'*override* (sovrascrivere) il metodo.

Nel grafico sotto UML vediamo che le sottoclassi *Circle*, *Square* e *Triangle*, sovrascrivono (*override*) i metodi *draw()* ed *erase()* di *Shape*. Nella terminologia dei linguaggi ad oggetti, si dice che nelle classi *Circle*, *Square* e *Triangle* viene eseguita &#x6C;**'override** dei metodi *draw()* e *erase()*. Ereditarietà e override dei metodi nelle sottoclassi sono gli ingredienti per il **Polimorfismo** (vedi paragrafo successivo).

![Overridding dei metodi](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVm6uVhj_2LUPEn6z_w%2F-LVmBck062adxcGWBjd3%2FIneritance_4.PNG?alt=media\&token=1262d207-edfc-4307-a5d0-e996af890c06)

Da notare che oggetti del tipo della sottoclasse possono essere assegnati a variabili della superclasse, in quanto ad esempio un oggetto di tipo *Circle* è anche una *Shape* (**is-a** in terminologia dei linguaggi ad oggetti).

```java
Shape sp = new Circle();
sp = new Triangle();
// or
sp = new Square();
```

Viceversa non è detto: potrebbe essere una *Shape* o ad esempio una forma differente a quella a cui sto facendo l'assegnamento. E' necessario un **cast esplicito**  (*downcast*) per fare l'assegnazione e se l'assegnamento non è valido, genera un'eccezione *java.lang.ClassCastException*.

Il *downcasting* richiede il cast espicito nella forma dell'operatore prefisso `(`*`new-type`*`)`. Come già detto l'operazione di downcast non è sempre sicura, e lancia una eccezione a runtime `ClassCastException` se l'istanza che su cui è eseguito il downcast non appartiene alla sottoclasse. Un oggetto di una sottoclasse può esssere sostituito a uno della superclasse, ma il contrario non è vero.

```java
Shape spA = new Triangle();
Triangle myTriangle = (Triangle) spA; // OK cast 

Square mySquare = (Square) spA; // throws ClassCastException
```

Per esempio su *uppercast* e *downcast* (cast espicito) vedi: [client/TestSubstitution.java](https://github.com/checksound/Polimorfismo/blob/master/src/client/TestSubstitution.java)

#### Polimorfismo

Per spiegare il polimorfismo partiamo da un esempio: il metodo **doSomething**  accetta qualsiasi oggetto di tipo **Shape**, quindi è indipendentemente dal tipo di oggetto passato per eseguire l'operazione di *erase* e *draw.*

```java
void doSomething(Shape shape) {
    shape.erase();
    // ...
    shape.draw();
}
```

Se in qualche altra parte del programma viene chiamato il metodo **doSomething()**:

```java
Circle circle = new Circle();
Triangle triangle = new Triangle(); 
Line line= new Line(); 
doSomething(circle); 
doSomething(triangle); 
doSomething(line);
```

La chiamata a **doSomething()** funziona correttamente indipendentemente dal tipo di oggetto passato.

Considera la linea:

```java
doSomething(circle);
```

Quello che succede quì è the un oggetto di tipo **Circle** è passato a un metodo che si aspetta un oggetto di tipo **Shape**. Siccome il tipo **Circle** è un tipo di **Shape**, il metdodo **doSomthing** lo può trattare come **Shape**.&#x20;

![Upcasting](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LVsbIS3npNV3pzzX0Q8%2F-LVsbfc_a_0lhzUyPUZ9%2FUpcasting.PNG?alt=media\&token=13869b8f-048f-4652-bf1e-f52f48f9ebe3)

Il termine *Upcasting* per come l'albero della gerarchia di classi è disegnato, con la classe base in alto.

Altro esempio, riguardo gli strumenti musicali sempre sul polimorfismo: scrivo il metodo `tune(Instrument i)` che prende come parametro un oggetto di tipo `Instrument` (superclasse della gerarchia degli strumenti musicali).

{% code title="polymorphism/music/Note.java" %}

```java
//: polymorphism/music/Note.java
// Notes to play on musical instruments.
package polymorphism.music;

public enum Note {
    MIDDLE_C, C_SHARP, B_FLAT; // Etc.
} ///:~
```

{% endcode %}

{% code title="polymorphism/music/Instrument.java" %}

```java
//: polymorphism/music/Instrument.java
package polymorphism.music;
import static net.mindview.util.Print.*;

class Instrument {
    public void play(Note n) {
        print("Instrument.play()");
    }
}
///:~

```

{% endcode %}

{% code title="polymorphism/music/Wind.java" %}

```java
//: polymorphism/music/Wind.java
package polymorphism.music;

// Wind objects are instruments
// because they have the same interface:
public class Wind extends Instrument {
    // Redefine interface method:
    public void play(Note n) {
        System.out.println("Wind.play() " + n);
    }
} ///:~
```

{% endcode %}

{% code title="polymorphism/music/Music.java" %}

```java
//: polymorphism/music/Music.java
// Inheritance & upcasting.
package polymorphism.music;

public class Music {
    public static void tune(Instrument i) {
        // ...
        i.play(Note.MIDDLE_C);
    }
    
    public static void main(String[] args) {
        Wind flute = new Wind();
        tune(flute); // Upcasting
    }
} 
/* Output:
Wind.play() MIDDLE_C
*///:~
```

{% endcode %}

#### Overloading invece di upcasting

Esempio per far vedere che se invece di sfruttare il polimorfismo nel metodo `tune(Instrument i)` nella classe `Music` dell'esempio sopra, avessi usato un metodo `tune` per ogni tipo di strumento, facendo quindi l'***overloading*** del metodo `tune()`:

{% code title="polymorphism/music/Music2.java" %}

```java
package polymorphism.music;

import static net.mindview.util.Print.*;

class Stringed extends Instrument {
    public void play(Note n) {
        print("Stringed.play() " + n);
    }
}

class Brass extends Instrument {
    public void play(Note n) {
        print("Brass.play() " + n);
    }
}
public class Music2 {
    public static void tune(Wind i) {
        i.play(Note.MIDDLE_C);
    }
    
    public static void tune(Stringed i) {
        i.play(Note.MIDDLE_C);
    }
    
    public static void tune(Brass i) {
        i.play(Note.MIDDLE_C);
    }
    
    public static void main(String[] args) {
        Wind flute = new Wind();
        Stringed violin = new Stringed();
        Brass frenchHorn = new Brass();
        tune(flute); // No upcasting
        tune(violin);
        tune(frenchHorn);
    }
} 
/* Output:
Wind.play() MIDDLE_C
Stringed.play() MIDDLE_C
Brass.play() MIDDLE_C
*///:~
```

{% endcode %}

Facendo l'**overloading** del metodo `tune()`, per ogni nuovo tipo di strumento (classe), dovrei aggiungere un metodo `tune` per quel particolare tipo di strumento: ad esempio `tune(Guitar i)` nella classe `Music2`, se aggiungo la classe `Guitar`, mentre con il polimorfismo `tune(Instrument i)` funzionerebbe correttamente senza bisogno di modifiche della classe `Music`, basta che il nuovo strumento `Guitar` sia sottoclasse di `Instrument`.

Si vede da questo esempio come il polimorfismo permetta di esendere il codice (ad esempio aggiungere un nuovo tipo di strumento) senza modificare il codice già scritto: il metodo `tune(Instrument i)` funziona correttamente anche con la nuova classe `Guitar`.

Esempio su overridding dei metodi <https://github.com/checksound/Polimorfismo>

## Definire un costruttore

Il costruttore serve per instanziare, creare, un' oggetto data una classe ad esempio

Modifichiamo la classe `Circle`

```java
public class Circle {
    public double x, y;   // The coordinates of the center
    public double r;      // The radius
    // Methods that return the circumference and area of the circle
    public double circumference() { return 2 * 3.14159 * r; }
    public double area() { return 3.14159 * r*r; }
}
```

definendo un costruttore:

```java
public class Circle {
    public double x, y, r;  // The center and the radius of the circle
    // The constructor method.
    public Circle(double x, double y, double r)
    {
        this.x = x;
        this.y = y;
        this.r = r;
    }   
    public double circumference() { return 2 * 3.14159 * r; }
    public double area() { return 3.14159 * r*r; }
}
```

Mentre con il vecchio, di default, costruttore, dovevamo scrivere il codice in questo modo:

```java
Circle c = new Circle();
c.x = 1.414;  
c.y = -1.0;  
c.r = .25;
```

Ora con il nuovo costruttore:

```java
Circle c = new Circle(1.414, -1.0, .25);
```

Ci sono due cose importanti da notare, circa il nome e la dichiarazione del costruttore:

* il costruttore ha lo stesso nome della classe;
* il tipo di ritorno è implicitamente un istanza della classe. Nessun return type è specificato nella dichiarazione del costruttore, neppure la parola chiave void è utilizzata. L'oggetto this è implicitamente ritornato; il contruttore non deve utilizzare return per restituire un valore;

### Costruttori multipli

Una classe può avere più costruttori:

```java
public class Circle {
    public double x, y, r;
    
    public Circle(double x, double y, double r) {
        this.x = x; this.y = y; this.r = r;
    }
    public Circle(double r) { x = 0.0; y = 0.0; this.r = r; }
    public Circle(Circle c) { x = c.x; y = c.y; r = c.r; }
    public Circle() { x = 0.0; y = 0.0; r = 1.0; }
    
    public double circumference() { return 2 * 3.14159 * r; }
    public double area() { return 3.14159 * r*r; }
    
    @Override
	public String toString() {
		return "Circle [x=" + x + ", y=" + y + ", raggio=" + r + "]";
	}
}
```

Nell'esempio un oggetto di tipo `Circle` può essere istanziato, utilizzando uno di questi costruttori e viene inizializzato in base al costruttore invocato, esempio:

```java
// costruttore senza argomenti
Circle circle1 = new Circle();
System.out.println("Circle1: " + circle1); // Circle1: Circle [x=0.0, y=0.0, raggio=1.0]
		
// costruttore un parametro double, il raggio
Circle circle2 = new Circle(5);
System.out.println("Circle2: " + circle2); // Circle2: Circle [x=0.0, y=0.0, raggio=5.0]
		
//costruttore con tre parametri double
Circle circle3 = new Circle(3.2, 2.5, 7);
System.out.println("Circle3: " + circle3); // Circle3: Circle [x=3.2, y=2.5, raggio=7.0]
		
Circle circle4 = new Circle(circle3);
System.out.println("Circle4: " + circle4); // Circle4: Circle [x=3.2, y=2.5, raggio=7.0]


```

### *Chiamare  un costruttore da un costruttore*

Quando scriviamo più costruttori per una classe, ci sono volte che verrebbe comodo chiamare un costruttore da un altro costruttore per evitare di duplicare del codice. Si può fare una simile chiamata usando la keyword **this**.

Normalmente, quando diciamo **this**, intendiamo nel senso di "questo oggetto" o "l'oggetto corrente" e in se stesso è la reference all'oggetto corrente. In un costruttore, la keyword **this** prende un diverso significato quando è seguita da una lista di argomento (anche vuota). Fa una chiamata esplicita al costruttore che corrisponde alla lista degli argomenti. Quindi abbiamo un modo semplice per chiamare altri costruttori.

```java
package prova;

public class Flower {
	int petalCount = 0;
	String s = "initial value";

	Flower(int petals) {
		petalCount = petals;
		System.out.println("Constructor w/ int arg only, petalCount= " + petalCount);
	}

	Flower(String ss) {
		System.out.println("Constructor w/ String arg only, s = " + ss);
		s = ss;
	}

	Flower(String s, int petals) {
		this(petals);
		// ! this(s); // Can’t call two!
		this.s = s; // Another use of "this"
		System.out.println("String & int args");
	}

	Flower() {
		this("hi", 47);
		System.out.println("default constructor (no args)");
	}

	void printPetalCount() {
		// ! this(11); // Not inside non-constructor!
		System.out.println("petalCount = " + petalCount + " s = " + s);
	}

	public static void main(String[] args) {
		Flower x = new Flower();
		x.printPetalCount();
	}
} 
/*
 * Output: Constructor w/ int arg only, petalCount= 47 String & int args default
 * constructor (no args) petalCount = 47 s = hi
 */// :~
```

Il costruttore `Flower(String s, int petals)` mostra che si può usare **this** per chiamare un altro costruttore, non potete usere **this** due volte. In aggiunta la chiamata al costruttore deve essere la prima istruzione altrimente si riceve un errore di compilazione.

In questo esempio si vede un altro modo in cui this può essere usato. Siccome il nome dell'argomento **s** e il nome del campo della classe **s** sono gli stessi per evitare l'ambiguità, si può utilizzare **this.s**, per dire che ci stiamo riferendo al dato membro.

Nel metodo **printPetalCount()** si può vedere che il compilatore non permette di chiamare il costruttore da nessun altro metodo se non il costruttore.

Riprendendo l'esempio di `Circle`, riscriviamo il codice, usando **this** ed evitando così duplicazioni di codice:

```java
public class Circle {
    public double x, y, r;
    public Circle(double x, double y, double r) { 
        this.x = x; this.y = y; this.r = r; 
    }
    public Circle(double r) { this(0.0, 0.0, r); }
    public Circle(Circle c) { this(c.x, c.y, c.r); }
    public Circle() { this(0.0, 0.0, 1.0); }

}
```

C'è una restrizione nell'utilizzo di *this( )*: può  esssere solo il primo statement del costruttore.&#x20;

Questa restrizione è legata all'invocazione automatica del costruttore della superclasse, meccanismo che verrà spiegato in seguito.

## Variabili di classe

```java
public class Circle {
    static int num_circles = 0; // class variable: how many circles created
    public double x, y, r;      // instance vars: the center and the radius
    public Circle(double x, double y, double r) {
        this.x = x; this.y = y; this.r = r;
        num_circles++;
    }
    public Circle(double r) { this(0.0, 0.0, r); }
    public Circle(Circle c) { this(c.x, c.y, c.r); }
    public Circle() { this(0.0, 0.0, 1.0); }
    public double circumference() { return 2 * 3.14159 * r; }
    public double area() { return 3.14159 * r*r; }
}
```

### Accesso alle variabili di classe

```java
System.out.println("Number of circles created: " + Circle.num_circles);
```

### Costanti, un altro esempio di variabili di classe

```java
public class Circle {
    public static final double PI = 3.14159265358979323846;
    public double x, y, r;
    // ... etc....
}
```

Oltre a `static` c'è la parola chiave `final` che significa che il valore della variabile non può più cambiare. Così non è possibile fare qualcosa come:

```java
Circle.PI = 4; // errore in compilazione
```

## Metodi di classe

```java
public class Circle {
    double x, y, r;
    // is point (a,b) inside this circle?  
    public boolean isInside(double a, double b)
    {
        double dx = a - x;
        double dy = b - y;
        double distance = Math.sqrt(dx*dx + dy*dy);
        if (distance < r) return true;
        else return false;
    }
        .
        .  // Constructor and other methods omitted.
        .
}
```

`Math.sqrt` è un metodo di classe della classe `Math` del JDK.

I metodi di classe sono definiti con l'identificativo `static`&#x20;

#### No *this* nei metodi di classe (static)

I metodi statici di classe differiscono da quelli di istanza per una cosa importante: non è passato il `this` al metodo automaticamente come avviene per i metodi di istanza.

### Definizione di un metodo static per Circle

```java
public class Circle {
    public double x, y, r;
    // An instance method.  Returns the bigger of two circles.
    public Circle bigger(Circle c) { 
        if (c.r > r) return c; else return this; 
    }
    // A class method.  Returns the bigger of two circles.
    public static Circle bigger(Circle a, Circle b) {
        if (a.r > b.r) return a; else return b;
    }
        .
        .  // Other methods omitted here.
        .
}
```

Invocazione di un metodo d'instanza così:

```java
Circle a = new Circle(2.0);
Circle b = new Circle(3.0);
Circle c = a.bigger(b);         // or, b.bigger(a);
```

Invocazione di un metodo di classe:

```java
Circle a = new Circle(2.0);
Circle b = new Circle(3.0);
Circle c = Circle.bigger(a,b);
```

#### L' inizializzazione statica

```java
// We can draw the outline of a circle using trigonometric functions.
// Trigonometry is slow though, so we pre-compute a bunch of values.
public class Circle {
    // Here are our static lookup tables, and their own simple initializers.
    static private double sines[] = new double[1000];
    static private double cosines[] = new double[1000];
    // Here's a static initializer "method" that fills them in.  
    // Notice the lack of any method declaration!
    static {
        double x, delta_x;
        int i;
        delta_x = (Circle.PI/2)/(1000-1);
        for(i = 0, x = 0.0; i < 1000; i++, x += delta_x) {
            sines[i] = Math.sin(x);
            cosines[i] = Math.cos(x);
        }
    }
        .
        .  // The rest of the class omitted.
        .
}
```

## Sottoclassi ed ereditarietà

Riprendiamo il concetto di sottoclassi ed ereditarietà.&#x20;

Un esempio:

```java
public class GraphicCircle extends Circle {
    // We automatically inherit the variables and methods of
    // Circle, so we only have to put the new stuff here.
    // We've omitted the GraphicCircle constructor, for now.
    Color outline, fill;
    public void draw(DrawWindow dw) { 
        dw.drawCircle(x, y, r, outline, fill); 
    }
}
```

Con la parola chiave `extends`    significa che `GraphicCircle` è una sottoclasse di `Circle` e che eredita di campi e metodi della superclasse.

Un' altra proprietà importante è che ogno oggetto di tipo `GraphicCircle` , è anche un oggetto di tipo `Circle`.

### Costruttore delle sottoclassi

```java
public GraphicCircle(double x, double y, double r, 
                                Color outline, Color fill)
{
    this.x = x; 
    this.y = y; 
    this.r = r;
    this.outline = outline; 
    this.fill = fill;
}
```

Questo construttore si basa sul fatto che la classe `GraphicCircle` eredita tutte le variabili da `Circle` e semplicemente inizializza lui stesso quelle variabili. Ma questo duplica il codice del costruttore di `Circle`, e se `Circle` facesse, nel costruttore, una inizializzazione più elaborata, la duplicazione, in `GraphicCircle` sarebbe complicata. Inoltre, se la classe `Circle` avesse attributi `private` (sono spiegati dopo) non potrebbe neppure inizializzarli direttamente, come abbiamo fatto sopra. Ciò di cui abbiamo bisogno è um modo per chiamare un costruttore di Circle, all'interno del nostro costruttore di `GraphicCircle`.

Nel codice sotto vediamo come si fa.

#### GraphicCircle costruttore con *super*

Invocazione del costruttore della superclasse:

```java
public GraphicCircle(double x, double y, double r, 
                                Color outline, Color fill) 
{
    super(x, y, r); // invoco costruttore di Circle
    this.outline = outline; 
    this.fill = fill;
}
```

Utilizzo di `super(...)` .&#x20;

`super` è una parola riservata di Java. Uno dei suoi utilizzi è mostrata in questo esempio - per invocare il costruttore della superclasse. Il suo utilizzo è analogo all'uso di `this` per invocare il costruttore di una classe dall'interno di un altro costruttore della stessa classe.

L'utilizzo di `super` per invocare un costruttore è soggetto alle stesse restrizioni dell'utilizzo di `this` per l'invocazione di un costruttore:

* super può essere solo usato in questo modo all'interno di un metodo costruttore;
* La chiamata al costruttore della superclasse deve essere la prima istruzione all'interno del costruttore;

### La catena dei costruttori e costruttore di *default*

Quando si definisce una classe, Java garantisce che il metodo costruttore della classe è invocato quando un'istanza della classe è creata. Inoltre garantisce che il costruttore è invocato anche quando un' istanza della sottoclasse è creata. Per garantire questo secondo punto, Java deve assicurare che ogni costruttore chiama un costruttore della superclasse. Se la prima istruzione nel costruttore non è la chiamata al costruttore della superclasse con la `super`, allora Java implicitamente aggiunge l'istruzione `super()` - cioè, chiama il costruttore della superclasse senza parametri. Se la superclasse non ha un costruttore senza parametri, viene generato un errore di compilazione.

C'è una eccezione alla regola che Java invoca `super()` implicitamente se non lo fai esplicitamente. Se la prima riga del costruttore, C1, usa la sintassi this() per invocare un altro costruttore, C2, della classe, Java si basa su C2 per invocare il costruttore della superclasse., e non inserisce in C1 la chiamata `super()`. Se, per esempio, anche C2 utilizzasse this() per invocare un terzo costruttore, allora anche C2 non chiamerebbe super(), ma un qualche costruttore della classe, esplicitamente o implicitamente dovrà invocare il costruttore della superclasse.

Considera cosa succede quando creiamo una nuova istanza di GraphicCircle. Prima, il costruttore di `GraphicCircle`, [codice](#graphiccircle-costruttore-con-super), è invocato. Questo costruttore esplicitamente invoca il costruttore di `Circle` e il costruttore di `Circle` implicitamente chiama `super()` per invocare il costruttore della superclasse, `Object`. In questo modo, il codice del costruttore di `Object` viene eseguito prima, seguito dal codice del costruttore di `Circle` e finalmente dal codice del costruttore di `GraphicCircle`.

Tutto questo vuol dire che le chiamate dei costruttori sono in catena, tutte le volte che un oggetto è creato, tutta la sequenza dei costruttori è invocata, dalla sottoclasse alla superclasse, fino ad `Object`, la radice della gerarchia delle classi. Siccome il costruttore della superclasse è sempre invocato come prima istruzione del costruttore, il codice del costruttore di `Object` sempre viene eseguito per primo, seguito del codice del costruttore di ogni sottoclasse, e giù per la gerarchia delle classi, fino alla classe che sta per essere istanziata.

Da tener anche presente che se nella classe non è specificato un costruttore, Java genera implicitamente un costruttore di default, che invoca `super()`. Esempio, se in `GraphicCircle` non fossero definiti dei costruttori, Java genera implicitamente questo costruttore:

```java
public GraphicCircle() { super(); }
```

Nota che se nella superclasse `Circle`, non c'è un costruttore senza argomenti (o quello di default o perchè dichiarati altri costruttori) allore dà errore di compilazione.

Vedi esempio [Circle e GraphicCircle - costruttori ed ereditarietà](https://github.com/checksound/EsempioCostruttoriEreditarieta).

### **Method Overriding & Variable Hiding**

L' esempio seguente serve a mostrare l'utilizzo di super per invocare metodi delle superclassi e von la versione sovrascritta (overridden) della sottoclasse.

![](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LXD9z_lzCvwj4O6uLP2%2F-LXDBNFUJbrH7ZXGLs0U%2FOOP_CircleCylinder.png?alt=media\&token=b1679ec0-5f56-4345-a4e8-45b40549bcf5)

Data una classe `Circle` deriviamo una sottoclasse `Cylinder`

{% code title="Circle.java" %}

```java
public class Circle {
   // private instance variables
   private double radius;
   private String color;

   // Constructors
   public Circle() {
      this.radius = 1.0;
      this.color = "red";
   }
   public Circle(double radius) {
      this.radius = radius;
      this.color = "red";
   }
   public Circle(double radius, String color) {
      this.radius = radius;
      this.color = color;
   }

   // Getters and Setters
   public double getRadius() {
      return this.radius;
   }
   public String getColor() {
      return this.color;
   }
   public void setRadius(double radius) {
      this.radius = radius;
   }
   public void setColor(String color) {
      this.color = color;
   }

   // Describle itself
   public String toString() {
      return "Circle[radius=" + radius + ",color=" + color + "]";
   }

   // Return the area of this Circle
   public double getArea() {
      return radius * radius * Math.PI;
   }
}
```

{% endcode %}

La sottoclasse `Cylinder`:

{% code title="Cylinder.java" %}

```java
/*
 * A Cylinder is a Circle plus a height.
 */
public class Cylinder extends Circle {
   // private instance variable
   private double height;
   
   // Constructors
   public Cylinder() {
      super();  // invoke superclass' constructor Circle()
      this.height = 1.0;
   }
   public Cylinder(double height) {
      super();  // invoke superclass' constructor Circle()
      this.height = height;
   }
   public Cylinder(double height, double radius) {
      super(radius);  // invoke superclass' constructor Circle(radius)
      this.height = height;
   }
   public Cylinder(double height, double radius, String color) {
      super(radius, color);  // invoke superclass' constructor Circle(radius, color)
      this.height = height;
   }
   
   // Getter and Setter
   public double getHeight() {
      return this.height;
   }
   public void setHeight(double height) {
      this.height = height;
   }

   // Return the volume of this Cylinder
   public double getVolume() {
      return getArea()*height;   // Use Circle's getArea()
   }

   // Describle itself
   public String toString() {
      return "This is a Cylinder";  // to be refined later
   }
}
```

{% endcode %}

La classe di test:

{% code title="TestCylinder.java" %}

```java
/*
 * A test driver for the Cylinder class.
 */
public class TestCylinder {
   public static void main(String[] args) {
      Cylinder cy1 = new Cylinder();
      System.out.println("Radius is " + cy1.getRadius()
         + " Height is " + cy1.getHeight()
         + " Color is " + cy1.getColor()
         + " Base area is " + cy1.getArea()
         + " Volume is " + cy1.getVolume());
   
      Cylinder cy2 = new Cylinder(5.0, 2.0);
      System.out.println("Radius is " + cy2.getRadius()
         + " Height is " + cy2.getHeight()
         + " Color is " + cy2.getColor()
         + " Base area is " + cy2.getArea()
         + " Volume is " + cy2.getVolume());
   }
}
```

{% endcode %}

Una sottoclasse eredita tutte le variabili membro e metodi dalla sua superclasse (quella padre e i suoi predecessori). Essa può utilizzare i metodi ereditati e le variabili così come sono. Può anche sovrascrivere un metodo ereditato provvedendo la propria versione (**overridding**), o nascondere la variabile ereditata definendo una variabile con lo stesso nome.

Per esempio, il metodo ereditato `getArea()` (da `Circle`) in un oggetto di tipo `Cylinder`, calcola l'area di base del cilindro. Supponiamo che vogliamo sovrascrivere il metodo `getArea()` per calcolare l'area di superfice del cilindro. Sotto ci sono le modifiche alla classe `Cylinder`:

{% code title="Cylinder.java" %}

```java
public class Cylinder extends Circle {
   ......
   // Override the getArea() method inherited from superclass Circle
   @Override
   public double getArea() {
      return 2 * Math.PI * getRadius() * height 
         + 2 * super.getArea();
   }
   // Need to change the getVolume() as well
   public double getVolume() {
      return super.getArea() * height;   // use superclass' getArea()
   }
   // Override the inherited toString()
   @Override
   public String toString() {
      return "Cylinder[" + super.toString() + ",height=" + height + "]";   
   }
}

```

{% endcode %}

Se `getArea()` è chiamato da un oggetto di tipo `Circle`, esso calcola l'area del cerchio. Se `getArea()` è invocato da un oggetto di tipo `Cylinder`, esso calcola l'area di superfice del cilindro, usando l'implementazione sovrascritta (*overridden*). Nota che bisogna utilizzare i metodti pubblici di accesso `getRadius()` per recuperare il valore di `radius` del `Circle`, perchè radius è dichiarato private e quindi non accessibile  dalle altre classi, neppure dalle sottoclassi (in questo caso `Cylinder`).

Ma se sovrascriviamo `getArea()` in `Cylinder`, il metodo `getVolume()` (`=getArea()*height`)  non è più corretto. Questo perchè il metodo nuovo, sovrascritto, `getArea()` sarà quello utilizzato nel metodo `getVolume()` di Cilinder, ma la nuova implementazione del metodo non calcola più l'area di base del cerchio (che a me servirebbe per calcolare il volume). Puoi correggere l'errore nel metodo `getVolume()` scrivendo `super.getArea()`, per utilizzare la versione di `Circle` del metodo `getArea()`.&#x20;

Esempio: <https://github.com/checksound/MethodOverridding-CircleAndCilinder>

## Data hidding e incapsulation

Uno dei principi fondamentali della programmazione ad oggetti è che all'esterno la classe esponga solo ciò che è utile perchè sia utilizzata, senza particolari inutili, ad esempio variabili di istanza della classe che non è appropriato che chi utilizza l'oggetto possa accedere e modificare, magari creando poi un comportamento non voluto riguardo l'utilizzo del metodo.  Il metdodo principale per nascondere variabili e metodi di istanza di una classe è tramite il modificatore d'accesso **private** messo davanti alla variabile o la dichiarazione del metodo. Questo fa si che anche le eventuali sottoclassi non possano accedere alla variabile e al metodo. Con il modificatore **private** abbiamo quindi la chiusora più totale: solo dall'interno della classe posso accedere a variabili e metodi dichiarati come **private**. Al contrario con la dichiarazione con il modificatore d'accesso **public** ho l'apertura più totale. Chiunque può invocare il metodo o accedere alla variabile (anche da classi in altri **package**, basta che importi la classe).

Situazioni intermedie si han il modificatore **protected**:  variabili o metodi dichiarati come protected sono accedibili da classi dello stesso pacchetto ma anche all'interno di sottoclassi anche se in **package** diversi.

Se non si mette nessun modificatore d'accesso alla variabile o al metodo, si ha l'accessibilità di tipo **package**, cioè sono accedibili solo da classi all'interno dello stesso **package**.

| Accessibile a:                        | public | protected | package | private |
| ------------------------------------- | ------ | --------- | ------- | ------- |
| Stessa classe                         | si     | si        | si      | si      |
| Classi stesso pacchetto               | si     | si        | si      | **no**  |
| Sottoclassi in pacchetto differente   | si     | si        | **no**  | **no**  |
| Non sottoclassi, pacchetti differenti | si     | **no**    | **no**  | **no**  |

Per un ripasso dei package, cosa sono, perché il codice è organizzato in package, vedi: <http://www3.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html>

## Classi astratte e interface

Le **interface** e le **classi astratte** provvedono a un meccanismo più strutturato per separare le interfacce (inteso come comportamento esposto da una classe) e l'implementazione.

Questi meccanismi non sono supportati in altri linguaggi, come il C++, fornendo un supporto solo indiretto a questi concetti. Il fatto che in Java esistano parole chiave (**abstract** e **interface**) indica che questi concetti sono così importanti da fornirgli supporto diretto.

Per prima cosa vedremo le classi astratte, che sono in un certo senso una via di mezzo tra le classi ordinarie e le interface. Sebbene il primo impulso sarebbe quello di creare le interface, le classi astratte sono uno strumento importante e necessario per costruire classi che hanno qualche metodo non implementato.

### Classi astratte

![abstact Instrument](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LXY0v-C6TQxHQA2C2en%2F-LXY1LCSG_Uj3hs2l9J7%2Fabstract_class_diagram.PNG?alt=media\&token=ead2e66d-c21d-4015-bef8-bdf7a7efae61)

Qui sotto l'esempio dell'orchestra modificato con l'uso di **abstract** class e metodi.

{% code title="interfaces/music4/Music.java" %}

```java
//: interfaces/music4/Music4.java
// Abstract classes and methods.
package interfaces.music4;

import polymorphism.music.Note;
import static net.mindview.util.Print.*;

abstract class Instrument {
	private int i; // Storage allocated for each

	public abstract void play(Note n);

	public String what() {
		return "Instrument";
	}

	public abstract void adjust();
}

class Wind extends Instrument {
	public void play(Note n) {
		print("Wind.play() " + n);
	}

	public String what() {
		return "Wind";
	}

	public void adjust() {
	}
}

class Percussion extends Instrument {
	public void play(Note n) {
		print("Percussion.play() " + n);
	}

	public String what() {
		return "Percussion";
	}

	public void adjust() {
	}
}

class Stringed extends Instrument {
	public void play(Note n) {
		print("Stringed.play() " + n);
	}

	public String what() {
		return "Stringed";
	}

	public void adjust() {
	}
}

class Brass extends Wind {
	public void play(Note n) {
		print("Brass.play() " + n);
	}

	public void adjust() {
		print("Brass.adjust()");
	}
}

class Woodwind extends Wind {
	public void play(Note n) {
		print("Woodwind.play() " + n);
	}

	public String what() {
		return "Woodwind";
	}
}

public class Music4 {
	// Doesn’t care about type, so new types
	// added to the system still work right:
	static void tune(Instrument i) {
		// ...
		i.play(Note.MIDDLE_C);
	}

	static void tuneAll(Instrument[] e) {
		for (Instrument i : e)
			tune(i);
	}

	public static void main(String[] args) {
		// Upcasting during addition to the array:
		Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() };
		tuneAll(orchestra);
	}
} /*
	 * Output: Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play()
	 * MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C
	 */// :~

```

{% endcode %}

Esempio invece della classe `Shape` resa **abstract**:

```java
public abstract class Shape {
    public abstract double area();
    public abstract double circumference();
}

class Circle extends Shape {
    protected double r;
    protected static final double PI = 3.14159265358979323846;
    public Circle() { r = 1.0; }
    public Circle(double r) { this.r = r; }
    public double area() { return PI * r * r; }
    public double circumference() { return 2 * PI * r; }
    public double getRadius() { return r; }
}

class Rectangle extends Shape {
    protected double w, h;
    public Rectangle() { w = 0.0; h = 0.0; }
    public Rectangle(double w, double h) { this.w = w;  this.h = h; }
    public double area() { return w * h; }
    public double circumference() { return 2 * (w + h); }
    public double getWidth() { return w; }
    public double getHeight() { return h; }
}
```

Esempio di utilizzo:

```java
Shape[] shapes = new Shape[3];          // Create an array to hold shapes.
shapes[0] = new Circle(2.0);            // Fill in the array...
shapes[1] = new Rectangle(1.0, 3.0);
shapes[2] = new Rectangle(4.0, 2.0);
double total_area = 0;
for(int i = 0; i < shapes.length; i++)
    total_area += shapes[i].area();     // Compute the area of the shapes.
```

### Interface

Con la parola chiave **interface** porta il concetto di abstract class ancora più in là. Con **abstract** permetteva di definire uno o più metodi non implementati, definendo l'interfaccia ma non la corrispettiva implementazione. L'implementazione è definita nelle sottoclassi. Con la parola chiave **interface** si crea una classe completamente astratta, una classe che non provvede alcuna implementazione. Permette al creatore di determinare il nome dei metodi, la lista degli argomenti, i tipi di ritorno, ma non l'implementazione del metodo.

Una **interface** dice: "Tutte le classi che implementano questa particolare interfaccia saranno con questa immagine". Quindi, ogni codice che utilizza una interface, sa quali metodi possono esser chiamati per quella interface, e basta. Così l'interface è utilizzata per stabilire il protocollo tra le classi.

Per fare una classe che conforma a una particolare interface (o insieme di interfacce), si usa la parola chiave **implements**, che dice: "L'interfaccia indica come appare, ma ora io sto facendo vedere come funziona". Il diagramma delle classi per l'esempio degli strumenti:

![interface Instrument](https://3264574854-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LVU7WiFKajQhwsnAlGh%2F-LXY5QfNPkLuzbu2fovF%2F-LXY5cHvisXqX5aqaYJj%2Finterface_instruments_class_diagrama.PNG?alt=media\&token=21a53310-997b-42dc-87ec-783d2525dd24)

Si può vedere dalla classi **Woodwind** e **Brass** che una volta che è implementata un'interfaccia, la implementazione diventa una classe ordinaria che può essere estesa nel modo normale.&#x20;

{% code title="interfaces/music5/Music5.java" %}

```java
//: interfaces/music5/Music5.java
// Interfaces.
package interfaces.music5;

import polymorphism.music.Note;
import static net.mindview.util.Print.*;

interface Instrument {
	// Compile-time constant:
	int VALUE = 5; // static & final
	// Cannot have method definitions:

	void play(Note n); // Automatically public

	void adjust();
}

class Wind implements Instrument {
	public void play(Note n) {
		print(this + ".play() " + n);
	}

	public String toString() {
		return "Wind";
	}

	public void adjust() {
		print(this + ".adjust()");
	}
}

class Percussion implements Instrument {
	public void play(Note n) {
		print(this + ".play() " + n);
	}

	public String toString() {
		return "Percussion";
	}

	public void adjust() {
		print(this + ".adjust()");
	}
}

class Stringed implements Instrument {
	public void play(Note n) {
		print(this + ".play() " + n);
	}

	public String toString() {
		return "Stringed";
	}

	public void adjust() {
		print(this + ".adjust()");
	}
}

class Brass extends Wind {
	public String toString() {
		return "Brass";
	}
}

class Woodwind extends Wind {
	public String toString() {
		return "Woodwind";
	}
}

public class Music5 {
	// Doesn’t care about type, so new types
	// added to the system still work right:
	static void tune(Instrument i) {
		// ...
		i.play(Note.MIDDLE_C);
	}

	static void tuneAll(Instrument[] e) {
		for (Instrument i : e)
			tune(i);
	}

	public static void main(String[] args) {
		// Upcasting during addition to the array:
		Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() };
		tuneAll(orchestra);
	}
} /*
	 * Output: Wind.play() MIDDLE_C Percussion.play() MIDDLE_C Stringed.play()
	 * MIDDLE_C Brass.play() MIDDLE_C Woodwind.play() MIDDLE_C
	 */// :~


```

{% endcode %}

Da notare che non è importante se si fa l'upcasting a una classe "regolare" chiamata `Instrument`, una classe abstact chiamata `Instrument` o un interface chiamata `Instrument`. Il comportamento è identico. Infatti si può vedere che il metodo `tune()` non ha nessun indizio se `Instrument` sia una classe normale, astratta o una interface.

Altro esempio:

```java
public interface Drawable {
    public void setColor(Color c);
    public void setPosition(double x, double y);
    public void draw(DrawWindow dw);
}
```

Implementazione di un'interface:

```java
public class DrawableRectangle extends Rectangle implements Drawable {
    // New instance variables
    private Color c;
    private double x, y;
    // A constructor
    public DrawableRectangle(double w, double h) { super(w, h); }
    // Here are implementations of the Drawable methods.
    // We also inherit all the public methods of Rectangle.
    public void setColor(Color c) { this.c = c; }
    public void setPosition(double x, double y) { this.x = x; this.y = y; }
    public void draw(DrawWindow dw) { 
        dw.drawRect(x, y, w, h, c);
    }
}
```

#### Utilizzo di interface

```java
Shape[] shapes = new Shape[3];          // Create an array to hold shapes
Drawable[] drawables = new Drawable[3]; // and an array to hold drawables.
// Create some drawable shapes.
DrawableCircle dc = new DrawableCircle(1.1);
DrawableSquare ds = new DrawableSquare(2.5);
DrawableRectangle dr = new DrawableRectangle(2.3, 4.5);
// The shapes can be assigned to both arrays.
shapes[0] = dc;   drawables[0] = dc;
shapes[1] = ds;   drawables[1] = ds;
shapes[2] = dr;   drawables[2] = dr;
// Compute total area and draw the shapes by invoking 
// the Shape and the Drawable abstract methods.
double total_area = 0;
for(int i = 0; i < shapes.length; i++) {
    total_area += shapes[i].area();    // Compute the area of the shapes.
    drawables[i].setPosition(i*10.0, i*10.0);
    drawables[i].draw(draw_window);    // Assume draw_window defined somewhere.
}
```

#### Implementazione di molte interface

```java
public class DrawableScalableRectangle extends DrawableRectangle
                implements Drawable, Scalable {
    // The methods of the Scalable interface must be implemented here.
}
```

#### Definizione costanti nelle interface

```java
class A { static final int CONSTANT1 = 3; }
interface B { static final int CONSTANT2 = 4; }
class C implements B {
    void f() { 
        int i = A.CONSTANT1;  // Have to use the class name here.
        int j = CONSTANT2;    // No class name here, because we implement
    }                         // the interface that defines this constant.
}
```

#### Estendere le interface

```java
public interface Transformable extends Scalable, Rotateable, Reflectable { }
public interface DrawingObject extends Drawable, Transformable { }
public class Shape implements DrawingObject { ... }
```
