7. Polimorfismo

Grazie all’ereditarietà è possibile definire due aggettivi per il tipo degli oggetti:

Definizione di polimorfismo

Ex.

public class Car{
	public static void start(Car p){
		if(p.canStart()){
			p.turnOn();
	}

	public static void main(String args[]){
		Car mycar = new ElectricCar("Tesla");
		start(mycar);
	}
}

Nella prima riga del metodo main viene dichiarato l’oggetto mycar: il suo tipo statico è Car, mentre il suo tipo dinamico, subito dopo l’esecuzione di quella riga di codice, è ElectricCar ed esso può comunque cambiare con l’esecuzione del programma.

Questo è un esempio di polimorfismo: è l’abilità che un elemento sintattico può usare per riferirsi a tipi differenti.

In Java, una variabile referenziata di tipo T può fare riferimento al tipo T oppure a un suo sottotipo.

Tipi statici e dinamici

Il tipo statico viene definito dalla dichiarazione, mentre quello dinamico viene definito dal costruttore usato per costruire l’oggetto.

Ex. Siano le due classi A e B, erede di A. Sia l’oggetto o, dichiarato come A o;: il suo tipo statico è A. Il tipo dinamico di o può essere:

NB: L’assegnamento tra due oggetti viene considerato come errore a compile time se i tipi statici non sono uguali.

Chiamata dei metodi

Car mycar = new ElectricCar();
mycar.canStart(); // OK, chiamo un metodo di Car
mycar.turnOn(); // OK, chiamo il metodo di ElectricCar
mycar.recharge(); // KO, recharge non è un metodo di Car
ElectricCar yourcar = new ElectricCar();
yourcar.recharge(); // OK, chiamo un metodo di Car

Overloading

In Java si ha overloading quando due o più metodi hanno lo stesso nome, ma hanno parametri diversi.

public class Point2D{
	public float distance(Point2D p){...}
}

public class Point3D extends Point2D{
	public float distance(Point3D p){...}
}

Binding dinamico

In Java, ogni volta che scriviamo x.m(P) (dove x è un oggetto, m un suo metodo e P la lista di parametri forniti al metodo), la JVM deve scegliere quale implementazione del metodo m utilizzare: questa scelta viene fatta in base al tipo dinamico dell’oggetto x e NON in base al suo tipo statico.

Il compilatore a runtime sceglie in base al tipo dinamico dell’oggetto l’implementazione del metodo che più si avvicina al metodo chiamato.

public class UsaCar {
	public static void start(Car a) {
		a.turnOn(); //defined in ElectricCar 
	}

	public static void main(String args[]) { 
		Car a1 = new Car("Ford");
		Car a2 = new ElectricCaral("T"); 
		a1.turnOn();
		// at run-time call implementation of Car
		a2.turnOn();
		// at run-time call implementation of ElectricCar
		start(a2);
		// only at run time you can know the actual type
	} 
}