public - Ca` Foscari

Transcript

public - Ca` Foscari
DAIS – Univ. Ca' Foscari Venezia
Programmazione
ad oggetti
Samuel Rota Bulò
Interfacce
●
●
●
●
●
●
Classi diverse possono condividere funzionalità comuni.
–
Es: classi che descrivono diverse forme geometriche possono avere in
comune funzionalità quali calcolo dell'area o del perimetro
–
Es: classi che descrivono collezioni (liste, vettori, insiemi)
Le interfacce sono tipi astratti che specificano solo firme di metodi
tralasciando l'implementazione.
Una classe che fornisce le implementazioni dei metodi può dichiarare di
implementare l'interfaccia.
Un'interfaccia, come nel caso delle Classi, viene dichiarata in un
file .java e gli identificatori hanno per convenzione la prima lettera
maiuscola.
I metodi di un'interfaccia sono automaticamente pubblici.
I metodi di un'interfaccia implementati da una classe devono essere
dichiarati pubblici.
public interface Shape
{
double getArea();
double getPerimeter();
}
Implementazione di interfacce
●
●
Una classe dichiara di implementare un'interfaccia attraverso la
keyword implements.
Una classe può implementare più interfacce contemporaneamente:
–
●
●
●
public class nomeClasse implements I1,I2,I3 { }
La classe può implementare altri metodi oltre a quelli
dell'interfaccia.
Un'interfaccia può essere implementata da più classi
Non possiamo istanziare direttamente un oggetto di tipo
interfaccia.
public class Rectangle implements Shape
{
...
public double getArea(){
return width*height;
}
public double getPerimeter(){
return 2*(width+height);
}
}
public class Circle implements Shape
{
...
public double getArea(){
return r*r*Math.PI;
}
public double getPerimeter(){
return 2*Math.PI*r;
}
}
Polimorfismo
●
●
●
●
●
Un'interfaccia rappresenta tutte le classi che la
implementano
Un oggetto di una specifica classe può essere assegnato ad
una variabile di tipo interfaccia se quell'interfaccia è
implementata dalla classe di appartenenza.
Assegnare una variabile di tipo interfaccia ad una classe
invece non è possibile a meno di effettuare un esplicito
casting di tipo.
Quando è lecito un assegnamento da una variabile di tipo S ad
una variabile di tipo T diciamo che S è sottotipo di T (S<:T)
o che T è supertipo di S.
Quando invochiamo il metodo di un oggetto attraverso una
variabile di tipo interfaccia entra in gioco il polimorfismo:
– Il metodo che verrà invocato effettivamente dipende dal
tipo concreto dell'oggetto a cui la variabile si
riferisce.
– Avviene una ricerca dinamica del metodo da invocare a
run-time.
Tipo statico e dinamico
●
●
●
●
Tipo di una variabile:
–
statico: tipo dichiarato
–
dinamico: il tipo dell'oggetto a cui la variabile riferisce.
Il tipo dinamico può cambiare a run-time
Il tipo dinamico di una variabile è sempre sottotipo del suo tipo
statico
Il casting (T) var causa un errore
–
A compile-time se T non è compatibile con il tipo statico di
var
–
A run-time se T non è compatibile con il tipo dinamico di var.
Viene generata un'eccezione ClassCastException.
●
Per verificare se il tipo dinamico di una variabile var è
sottotipo di T usiamo l'operatore instanceof:
–
var instanceof T
–
errore a compile-time se T e il tipo statico di var non sono
in relazione di sottotipo/supertipo
Esempio
Shape anyShape=new Rectangle(0,0,1,1);
Shape anotherShape=new Circle(2);
Shape againAShape=new Stack(); // ERRORE ! Stack non implementa Shape
System.out.println(anyShape.getArea()); //cosa stampa?
System.out.println(anotherShape.getArea()); //cosa stampa?
anotherShape=anyShape;
System.out.println(anotherShape.getArea()); //cosa stampa?
anotherShape=new Circle(1);
Rectangle r=anyShape; // ERRORE !
Rectangle r2= (Rectangle) anyShape; // OK
Rectangle r3= (Rectangle) anotherShape; //ERRORE! È un Circle !
System.out.println(r instanceof Shape) // true
System.out.println(r instanceof Circle) //ERRORE
System.out.println(anyShape instanceof Shape) // true
System.out.println(anyShape instanceof Circle) // false
Ereditarietà di interfacce
●
Un'interfaccia può ereditare metodi da una o più
interfacce con la keyword extends.
public interface nomeInterfaccia extends I1,I2,I3{
//altri metodi
}
●
Se l'interfaccia J estende l'interfaccia I1 allora J è
sottotipo di I1.
public interface AreaComputable{
public double getArea();
}
public interface PerimeterComputable{
public double getPerimeter();
}
AreaComputable
PerimeterComputable
Shape
public interface Shape extends AreaComputable, PerimeterComputable
{
}
Cicli
while(cond)
{
// istruzioni
}
●
●
Itera fintantoché cond è vera
Condizione verificata
all'inizio del ciclo
for(expr1 ; cond ; expr2)
{
// istruzioni
}
●
●
●
Esegue expr1 all'inizio prima
di iniziare a iterare
Itera fintantoché cond è vera
Alla fine di ogni ciclo esegue
expr2
do
{
// istruzioni
}while(cond);
●
●
Itera fintantoché cond è vera
Condizione verificata alla fine
del ciclo
for(nomeTipo var1: collection)
{
// istruzioni
}
●
●
Il tipo di collection deve essere
sottotipo dell'interfaccia Iterable o
di tipo array
Itera sugli elementi dell'array/
iterable assegnandoli a var1
Cicli
int[] a={5,4,3,2,1};
for(int i=0;i<a.length;++i)
System.out.println(a[i]);
for(int v:a)
System.out.println(v);
int i=0;
while(i<a.length)
{
System.out.println(a[i]);
++i;
}
public interface Iterable<T>
{
Iterator<T> iterator();
}
Approfondiremo i tipi parametrizzati
più avanti. Nel caso delle strutture
dati come per esempio ArrayList il
tipo parametrico T rappresenta il
tipo degli elementi della struttura e
viene specificato in fase di
dichiarazione
ArrayList<int> list=new ArrayList<int>(); //ArrayList<int> implementa Iterable<int>
l.add(1); l.add(2);
for(int i:list)
System.out.println(i);
Java Collections
Iterable<E>
Collection<E>
Set<E>
List<E>
TreeSet<E>
ArrayList<E>
HashSet<E>
LinkedList<E>
LinkedHash<E>
...
...
Map<K,V>
Queue<E>
SortedMap<K,V>
PriorityQueue<E>
...
HashMap<K,V>
LinkedHashMap<K,V>
...
TreeMap<K,V>
...
Wrappers
●
●
A differenza degli array le collezioni possono
contenere solo elementi di tipo riferimento.
Se vogliamo creare collezioni di tipi primitivi
dobbiamo ricorrere a delle classi wrapper che
incapsulano il tipo primitivo.
Tipo primitivo
byte
boolean
char
double
float
int
long
short
Wrapper
Byte
Boolean
Char
Double
Float
Int
Long
Short
Auto-boxing
●
●
Da Java 5.0 la conversione tra tipi primitivo e i
corrispondenti tipi wrapper è automatica.
Attenzione: l'operatore di confronto == se applicato a
due wrapper non confronta i valori incapsulati ma i
riferimenti !!
Double d=1.;
int i=new Integer(2);
d=2+d+i;
System.out.println(d); // stampa 5.0
ArrayList<Double> list=new ArrayList<Double>();
list.add(9.);
List.add(new Double(3));
ArrayList<double> list2=new ArrayList<double>();
list2.add(4.);
list2.add(new Double(8));
System.out.println(1 == new Integer(1)); //true
System.out.println(new Integer(1) == new Integer(1)); //false !
Tipi enumerazione
●
I tipi enumerazione sono tipi che descrivono un insieme finito di
valori costanti.
public enum Day{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
FRIDAY, SATURDAY, SUNDAY
}
●
●
●
●
I tipi enumerazione possono essere utilizzati con il costrutto
switch
Una dichiarazione di enumerazione è una dichiarazione di classe a
tutti gli effetti
– può avere metodi e campi
–
non può avere costruttori pubblici
–
eredita da java.lang.Enum
Le costanti che elenchiamo saranno le uniche istanze di questa
classe. Devono essere elencate prima di tutto e terminare con ; se
prevediamo di aggiungere altro dopo.
Le costanti vengono create previa implicita invocazione di un
costruttore sulla base dei parametri associati alla costante.
Tipi enumerazione
public enum Planet{
MERCURY (3.303e+23, 2.4397e6), VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6), MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7), SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7), NEPTUNE (1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass; this.radius = radius;
}
public double mass() { return mass; }
public double radius() { return radius; }
public static final double G = 6.67300E­11;
public double surfaceGravity() {
return G * mass / (radius * radius);
}
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
}
Tipi enumerazione
Planet p=Planet.MERCURY;
switch(p)
{
case Planet.MERCURY: System.out.println(“Mercurio.”); break;
case Planet.URANUS: System.out.println(“Uranio.”); break;
default: System.out.println(“Altro pianeta.”);
}
System.out.println(p.mass()) // stampa 3.303e+23