Indice

Confronti tra elementi

PREV Subtyping & wildcards NEXT Dichiarazioni di variabili

Parleremo di Comparable<T>

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

Consistente con l'uguaglianza

x.equals(y) ↔ x.compareTo(y) == 0

Attenzione all'inserimento in SortedList ecc …

compareTo VS equals

BigDecimal non è consistente con l'uguaglianza

Contratto per comparable

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:

Underfow:

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

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)

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: