Il Poliformismo in Java – Parte 2

      Nessun commento su Il Poliformismo in Java – Parte 2

java-logo

Java implementa tutte le quattro forme di polimorfismo

Schermata 2014-03-22 alle 17.32.17

Poliformismo per inclusione

Si parla di polimorfismo per inclusione quando del codice scritto nei termini della classe/tipo A può essere utilizzato sostituendo all’oggetto di tipo A un altro oggetto di tipo B, per il fatto che è possibile considerare B un sottotipo di A. In Java, classe/sottoclasse permette di realizzare il polimorfismo per inclusione (Non bisogna però confondere la relazione classe/sottoclasse con la relazione tipo/sottotipo!)anche l’uso di interfacce permette di realizzare il polimorfismo per inclusione.  Come abbiamo detto nelle lezioni precedenti tutte le classi discendono da Object, una variabile di classe Object potrà essere assegnata a qualsiasi oggetto, di conseguenza un metodo con parametri di classe Object potrà dunque accettare oggetti di qualunque tipo, nello stesso modo è possibile restituire un oggetto di classe Object per mantenere la massima genericità, in realtà è sempre garantita la compilazione ma non il corretto funzionamento!

Schermata 2014-03-22 alle 17.43.34

Poliformismo per inclusione: Interfacce 

Scrivere il codice in termini di interfacce è un metodo efficace di sfruttare il polimorfismo per inclusione in Java, lavorando in termini di Object si mantiene la genericità a scapito dell’espressività: gli oggetti potranno usare esclusivamente i servizi della classe Object, viceversa, utilizzare una classe base limita nella pratica la genericità del codice, “appesantita” dall’implementazione. Utilizzando un’interfaccia si potranno utilizzare tutti i metodi definiti dalla stessa (oltre ai metodi della classe Object!)

Schermata 2014-03-22 alle 17.47.04 

In generale, una struttura con alla base una o più interfacce e una classe astratta permette di sfruttare al meglio riuso e la genericità, es:

Schermata 2014-03-22 alle 17.48.53

Poliformismo universale: Parametrico

I  generics sono lo strumento fornito da Java per realizzare il polimorfismo parametrico  essi  permettono di utilizzare un parametro nella definizione di metodi/classi, il cui tipo viene determinato in fase di instanziazione, Il comportamento e le funzionalità dei generics sono simili a quelle dei template in C++ .

Es

List<Integer> myIntList = new LinkedList();
myIntList.add(new Integer(0));

Integer i =myIntList.getFirst();

La sintassi per la definizione di una classe generica è la seguente:

modificatore_di_accesso class NomeClasse<E> {

modificatore_di_accesso tipo_restituito

nomeMetodo(E par1, …);

}

Esempio

public class ArrayList<E> {

void add(E x);

...

}
Un’ altro aspetto molto interessante è che è possibile limitare un tipo generico lungo una catena di eredità. Questo permette di utilizzare i servizi della classe/interfaccia base

Schermata 2014-03-22 alle 17.54.41

Istanziare classi generiche 

Quando viene istanziato un oggetto, è possibile indicare il tipo: tutte le occorrenze dei parametri formali di tipo sono sostituiti dal parametro specificato

List<Integer> al = new ArrayList<Integer>(); 

Piccolo approfondimento sui generics

Il tipo generico è quasi completamente gestito in tempo di compilazione, generando un bytecode unico che non dipende dai tipi parametrici, inoltre un tipo generico istanziato su un tipo funziona per inclusione anche con i sottotipi.

  • Una collezione di Object potrà contenere oggetti di qualunque tipo
  • Una collezione di Object non è superasse di una collezione con parametri più specifici

Es

</pre>
<div title="Page 16">
<div title="Page 16">
<div>
<div>
<pre>List <Object> l = new ArrayList<Object>();
l.add(new String());//OK!
l = new ArrayList<String>();//NO!</pre>
</div>
</div>
</div>
</div>
<pre>
 
In generale non vale la seguente corrispondenza 

Schermata 2014-03-22 alle 18.00.56 

Il “supertipo” di tutte le collezioni è: Collection<?>  nota anche come “collezione di sconosciuti”, Il simbolo ? è chiamato “tipo wildcard”

Esempio: 

 

<span style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px;">List <?> l = new ArrayList<String>();//OK</span></pre>
<div title="Page 19">
<div>
<div>
<pre>l = new ArrayList<Integer>();//OK!</pre>
</div>
</div>
</div>
<pre>
I wildcard limitati permettono di specificare un tipo generico il cui parametro appartiene a una catena d’eredità <? extends SuperClass> 
Esempio
void moo(List <? extends Number> l){
   l = new LinkedList <Double>();//OK!!
   l = new LinkedList <Integer>();//OK!!
   l = new LinkedList <Number>();//OK!!
   l = new LinkedList <String>();//NO!!


} 

 

Metodi Generici

Così come abbiamo visto per le classi, i metodi possono essere definiti generici, Il tipo generico può comparire come parametro, direttamente o indirettamente.

La sintassi generica è la seguente: 

modificatore_di_accesso <T [extends C]> tipo_restituito nomeMetodo

(…, [tipoGen<T> tipoG,] [T parG,][T[] arrG,] … ) 

Esempio

public class C {


static <T> Collection<T> arrayToCollection(T[] a){ Collection<T> c = new ArrayList();
 for (T o : a) {

c.add(o);

}

return c;

}
  public static void main(String[] args) {
    Collection<String> c =arrayToCollection(args);


}

} 

 

Tale metodo può essere usato con qualsiasi tipo di array/collezione :
 Object[] oa = new Object[100];
 Collection<Object> = C.fromArrayToCollection(oa);
 String[] sa = new String[100];
 Collection<String> cs = C.fromArrayToCollection(cs);


Metodi Generici e Wildcards

Quando usare i metodi generici e quando i wildcards?

  • Quando si vuole permettere ad un metodo di poter avere una varietà di tipi di argomenti attuali si usano i wildcards
  • Quando si vogliono esprimere dipendenze tra i tipi di uno o più argomenti di un metodo e/o per il suo tipo restituito si usano i metodi generici