Sei sulla pagina 1di 29

Programmazione a Oggetti

AA 2015-16
lezione 14 26/10/2015 14:00-15:30

Cast
public class Cast {
public static void main(String [] args){
Object o = new String("a");
String s = (String) o;
s.concat("b");
Object o2 = new Cast();
String s2 = (String) o2;//Eccezione!
s2.concat("c");
}
}

Output cast
Exception in thread "main"
java.lang.ClassCastException:
lezione13.Cast cannot be cast to
java.lang.String
at lezione13.Cast.main(Cast.java:11)
Java Result: 1

ClassCastException

Unchecked

Evita di eseguire codice potenzialmente pericoloso

Il compilatore accetta un cast solo tra una classe


base a una sua sottoclasse: (String estende
Object e Cast estende Object)
Il compilatore non accetta cast tra classi
incompatibili.
Al run time la JVM verifica effettivamente che il cast
sia vero.

Cast incompatibile
public static void main(String [] args)
{
Object o = new String("a");
String s = (String) o;
s.concat("b");
Cast c2 = new Cast();
String s2 = (String) c2;
s2.concat("c");
}

Cast compatibile
public static void main(String [] args){
Object o = new String("a");
String s = (String) o;
s.concat("b");
Cast c2 = new Cast();
String s2 = (String)(Object) c2;
s2.concat("c");
}

Cast
In pratica l'operatore di cast:

In compilazione non fa altro che assumere che


il tipo sia quello specificato nel cast
Al run-time controlla che la classe effettiva
dell'oggetto sia instanceof di quella
specificata nel cast (anche un sottotipo va
bene)

Metodi e classi abstract


Negli esempi fatti di estensione di classi, si partiva
da una classe funzionante e se ne derivava una
nuova con un comportamento simile ma
differente.
Delle volte si definisce una classe base con il solo
scopo di volerla estendere. Quindi la classe base
di per se stessa inutile. Solo quando derivata
assume un senso completo.

Metodi e classi abstract


Quando ha senso avere una classe base non
completa?

Mancano alcuni particolari e non possiamo sapere


come implementare alcuni metodi
Implementare uno o pi metodi pu essere difficile
o non orientato agli oggetti
L'implementazione di alcuni metodi deve essere
fatta da un altro team
L'implementazione di alcuni metodi crea
dipendenze non necessarie.

Esempio
public class Animale{
double peso;
String nome;
java.util.Date nascita;
String specie;//

public double getEta(){


return now()-nascita;
}

Esempio
public class Animale{

public void faiVerso(){


if (specie.equals("Cane"))
System.out.println("bau");
else if (specie.equals("Gatto"))
System.out.println("miao");
//sequenza molto lunga di if

Esempio

public Medicina trovaCura(String malattia){


if (specie.equals("Cane")){
if (getEta()>3 && malattia.equals())
return new AntibioticoA(peso*0.0001);
else ...
}
if (specie.equals("Tartaruga"){
if (getEta()>6 && malattia.equals())
return new AntibioticoB(peso*0.0002);
else ...
}

Esempio

public Pasto preparaPasto(){


Pasto pasto = new Pasto();
if (specie.equals("Cane")){
if (getEta()>1)
pasto.add(new Carne(peso*0.001));
else
pasto.add(new Acqua(peso*0.003));
} else if (specie.equals("Gatto"){
if (getEta()>0.5)
pasto.add(new Pesce(peso*0.002);
} else if ...
return pasto;
}

Esempio

Metodi troppo complessi: difficili da leggere;


molto tempo per scriverli; non sono
incrementali;
Fanno riferimento al tipo dell'oggetto: if
(specie.equals(Cane));
La classe Animale troppo complessa: chi la
implementa deve conoscere il comportamento
di tutti gli animali!

Approccio Polimorfo
OO suggerisce di organizzare il codice in un altro
modo:

Una classe base che si chiama Animale con


tutto il codice comune alle varie specie di
animali
Una classe derivata per ogni specie diversa di
animale: Cane, Gatto, Tartaruga, etc.
Si comincia a implementare solo le classi
necessarie

Approccio Polimorfo

Le classi derivate ridefiniscono (override) i


metodi che devono avere un comportamento
diverso per la specie particolare di animale
Per sfruttare polimorfismo (ovvero il principio di
sostituzione) bisogna che la classe Animale
definisca tutti i metodi che poi verranno ridefiniti
dalle classi derivate
Per esempio, se la classe base non definisse il
metodo preparaPasto il codice seguente non
potrebbe funzionare

Esempio

public static void main(String [] args){


Animale [] a = loadAnimali();
while (true){
for (int i=0; i<a.lenght; i++){
Pasto p = a[i].preparaPasto();
a[i].mangia(p);
}
aspetta12Ore();
}
}

Cane
public class Cane extends Animale{
@Override public Pasto preparaPasto(){
Pasto pasto = new Pasto();
if (getEta()>1)
pasto.add(new Carne(peso*0.001));
else
pasto.add(new Acqua(peso*0.003));
}
@Override public Medicina trovaCura(String malattia){
if (getEta()>3 && malattia.equals())
return new AntibioticoA(peso*0.0001);
else
}
}

Gatto
public class Gatto extends Animale{
@Override public Pasto preparaPasto(){
Pasto pasto = new Pasto();
if (getEta()>0.5)
pasto.add(new Pesce(peso*0.002);
} else if ...
}
@Override public Medicina trovaCura(String malattia){
if (getEta()>1 && malattia.equals())
return new AntibioticoC(peso*0.00005);
else
}
}

Tartaruga

Come esercizio scrivete la classe Tartaruga

Esempio
public class Animale{
double peso;
String nome;
java.util.Date nascita;
String specie;
String verso;
public Animale(String verso){
this.verso=verso;
}
public void faiVerso(){
System.out.println(verso);
}
public double getEta(){
return now()-nascita;
}

Come definiamo i metodi trovaCura e


preparaPranzo nella classe Animale?
Se non li definiamo del tutto, non possiamo usare
i metodi sugli oggetti generici (vedi esempio
sopra)
implementarli correttamente per tutti gli animali
impossibile
Implementarli parzialmente pu essere
pericoloso: potremmo dare una medicina
sbagliata a un'animale nuovo.

abstract

Java permette di definire nella classe Animale


solo la firma dei metodi, senza nessuna
implementazione (senza {}) dichiarandoli
abstract.
Una classe che definisca anche un solo metodo
abstract va definita abstract lei stessa.
Una classe abstract non pu essere istanziata
(non possiamo usare new Animale()!)
Se una sottoclasse ri-definisce tutti i metodi
abstract pu essere istanziata.

Esempio
public abstract class Animale{
double peso;
String nome;
java.util.Date nascita;
String specie;
String verso;
...
public abstract Medicina trovaCura(String m);
public abstract Pasto preparaPasto();
}

abstract

Dichiarando un metodo abstract esplicitamente


assegniamo la responsabilit della definizione del
metodo alla classe derivata
Chi implementer la classe derivata sar
responsabile della definizione dei metodi
trovaCura e preparaPasto.
Il compilatore controlla che tutti le regole vengano
rispettate
Non ci si pu dimenticare di implementare un
metodo su una classe istanziabile

Esempio
public abstract class Animale{
double peso;
String nome;
java.util.Date nascita;
String specie;
String verso;
public Animale(String verso){
this.verso=verso;
}
public void faiVerso(){
System.out.println(verso);
}
public double getEta(){
return now()-nascita;
}
public abstract Medicina trovaCura(String m);
public abstract Pasto preparaPasto();
}

Cane
public class Cane extends Animale{
public Cane(){super("bau");}
@Override public Pasto preparaPasto(){
Pasto pasto = new Pasto();
if (getEta()>1)
pasto.add(new Carne(peso*0.001));
else
pasto.add(new Acqua(peso*0.003));
}
@Override public Medicina trovaCura(String malattia){
if (getEta()>3 && malattia.equals())
return new AntibioticoA(peso*0.0001);
else
}
}

Abstract class

Una classe deve essere dichiarata abstract


quando almeno un metodo definito
abstract.
Un classe pu essere dichiarata abstract
anche se nessun metodo definito abstract:

Per sempio, nella seconda parte del corso vedrete


un esempio in cui ha senso avere una classe
astratta anche se definisce tutti i metodi: non si
vuole che la classe base sia istanziabile.

Domande