martedì 17 gennaio 2012

Introduzione a java e generics parte 3 - Confronti tra element


Parleremo di Comparable<T>
  • Confrontare elementi
  • Trovare massimo e minimo in una collezione
  • Metodi bridge

Comparable

public interface Comparable<T>
{
public int compareTo(T elem);
}
Il metodo compareTo restituisce un valore che è negativo, zero o positivo a seconda che il parametro fornito sia rispettivamente minore, uguale o maggiore del parametro implicito (this). Quando una classe implementa Comparable l'ordine specifcato dalla sua interfaccia è chiamato ordine naturale per la classe.

Mele con mele e pere con pere

Integer i0 = 0;
Integer i1 = 1;
assert i0.compareTo(i1) < 0;
String s0 = "zero";
String s1 = "uno";
assert s0.compareTo(s1) > 0;
(Di norma) un oggetto di una classe può essere confrontato solo con oggetti della stessa classe (pere con pere, mele con mele)
:!: Posso confrontare mele con pere?
Number n1 = 1;
Number npi = 3.14;
assert n1.compareTo(npi) <0; // Errore di compilazione
  • Notare il boxing
  • Il codice non compila!
  • Number non implementa Comparable

Consistente con l'uguaglianza

x.equals(y) ↔ x.compareTo(y) == 0
Attenzione all'inserimento in SortedList ecc …
compareTo VS equals
  • x.equals(null) → true, false
  • x.compareTo(null) → NullPointerException
BigDecimal non è consistente con l'uguaglianza

Contratto per comparable

  • Antisimmetrica
    • sgn(x.compareTo(y)) = - sgn(y.compareTo(x))
  • Transitiva
    • x.compareTo(y) < 0 & y.compareTo(z) < 0 → x.compareTo(z) <0
  • Congruenza
    • x.compareTo(y) == 0 → sgn(x.compareTo(z)) == sgn(y.compareTo(z))
  • Rifessiva
    • x.compareTo(x) == 0
sgn(x) è il segno di x: -1 negativo, 0 zero, 1 positivo

Overflow / underflow

:!: Attenzione
public int compareTo(Integer o) {
return this.value - o.value;
}
NO! Può generare overfow: confrontando un numero negativo grande in modulo con un grande numero positivo → Si può superare Integer.MAX_VALUE
Overflow:
  • Numero troppo grande in valore assoluto Maggiore di Integer.MAX_VALUE o minore di Integer.MIN_VALUE
Underfow:
  • numero, diverso da zero, troppo piccolo in valore assoluto per essere rappresentato dalla macchina

Trovare il massimo di una collezione

public static <T extends Comparable<T>> T max (Collection<T> coll){
 T cand = coll.iterator().next();
  for (T elem: coll){
  if (cand.compareTo(elem) < 0) cand = elem;
 }
 return cand;
}

Limiti

 <T extends Comparable<T>>
si dice che T è limitato da Comparable T Si è quindi posto un limite sul tipo di T. Il limite può essere ricorsivo
 <T extends C<T,U> , U extends D<T,U>>

Esempi

List<String> stringhe = Arrays.asList("ciao","mondo"); // ok
assert Collections.max(stringhe).equals("mondo" ); // ok 
List<Integer> interi = Arrays.asList(1,2,3); assert Collections.max(interi) == 2; // ok
List<Number> numeri = Arrays.asList(1 ,2 ,3 ,4 ,5 ,3.14); // ok
assert Collections.max(numeri) == 5; // NO! Il codice con compila

E' possibile utilizzare firme il più generiche possibile

public static <T extends Comparable<T>> T max (Collection<T> coll)
 
public static <T extends Comparable<? super T>> T max ( Collection<? extends T > elements)
 
public static <T extends Object & Comparable<? super T>> T max( Collection<? extends T> coll ) {

Limiti multipli

public static <S extends Readable & Closeable,
 T extends Appendable & Closeable>
 void copy(S src, T dest, int dim)throws IOException{
  CharBuffer buff = CharBuffer.allocate(dim);
  int i = src.read(buff);
  while (i >= 0 ){
   buff.flip(); // prepara per la scrittura
   dest.append(buff);
   buff.clear();
   i = src.read(buff);
  }
src.close(); dest.close();
}

Metodi bridge

Generics sono implementati mediante Type erasure
  • Il bytecode è piuttosto simile (e compatibile) con la versione senza Generics
Classi che implementano interfacce generiche (es: Comparable<T> )
  • Vengono aggiunti dal compilatore alcuni metodi detti metodi bridge
public class Foo1 implements Comparable {
 private final String value ;
 public Foo1(String value) {
  super();
  this.value = value;
 }
 public int compareTo(Object o) {
  return compareTo((Foo1)o);
 }
 public int compareTo(Foo1 o){
 return value.compareTo(o.value);
 }
}
Esempio di Comparable senza Generics. Il metodo classico chiama il metodo ridefnito dopo un cast (double dispatch). Attenzione! Java supporta il binding dinamico solamente sull'argomento implicito (this) e non sui parametri formali (quelli tra parentesi)

Con i generics

public class Foo2 implements
Comparable<Foo2> {
private final String value;
public Foo2(String value) {
this.value = value;
}
public int compareTo(Foo2 o) {
return value.compareTo(o.value);
}
}
C'è solo un metodo nel codice sorgente Vediamo cosa succede nel bytecode generato dal compilatore …

Bytecode generato con metodo bridge

for (Method m :
Foo2.class.getMethods()){
if (m.getName()
.equals("compareTo")) {
System.out.println(
m.toGenericString());
} }
----------------------
public int Foo2.compareTo(Foo2)
public bridge int Foo2.compareTo(java.lang.Object)

Override covariante (finalmente!)

In java ⇐ 1.4 un metodo può sovrascrivere un altro ↔ le due frme coincidono esattamente.
In java >= 5 un metodo può sovrascrivere un altro se gli argomenti sono identici ed il tipo di ritorno del metodo riscrivente è un sottotipo del tipo di ritorno del metodo riscritto.

Override <= 1.4

public class OldPunto {
private final int x;
private final int y;
public OldPunto(int x, int y) {
this.x = x;
this.y = y;
}
public Object clone() {
return new OldPunto(x, y);
Object ha un metodo clone() che restituisce un Object

Override >= 5.0

public class NewPunto {
private final int x;
private final int y;
public NewPunto(int x, int y) {
this.x = x;
this.y = y;
}
public NewPunto clone() {
return new NewPunto(x, y);
}
}
NewPunto è sottotipo di Object quindi non ci sono errori di compilazione
Vediamo se ci sono dei bridge:
public NewPunto NewPunto.clone()
public bridge java.lang.Object NewPunto.clone() throws java.lang.CloneNotSupportedException

Ancora sui bridge

A seconda del compilatore la dicitura bridge:
  • Può non comparire!
  • Può essere sostituita da volatile! (bug)
  • Altro …
  • Nel compilatore java6 di Apple non compare bridge

Nessun commento:

Posta un commento