PREV Subtyping & wildcards NEXT Dichiarazioni di variabili
Parleremo di Comparable<T>
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.
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
x.equals(y) ↔ x.compareTo(y) == 0
Attenzione all'inserimento in SortedList ecc …
compareTo VS equals
BigDecimal non è consistente con l'uguaglianza
sgn(x) è il segno di x: -1 negativo, 0 zero, 1 positivo
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:
Underfow:
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; }
<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>>
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
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 ) {
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(); }
Generics sono implementati mediante Type erasure
Classi che implementano interfacce generiche (es: Comparable<T> )
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)
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 …
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)
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.
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
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
A seconda del compilatore la dicitura bridge: