Implementujeme interface Comparable, jeho jedinou metodu, compareTo, která dokáže porovnat dva různé objekty. Jedním z porovnávaných objektů je příjemce zprávy, druhý je předán v argumentu volání metody. Metoda vrací kladné celé číslo, pokud je this větší než argument, záporné číslo, pokud je menší než argument, popřípadě 0, pokud jsou stejné.
Pomocí operace porovnání dvou objektů je řešeno například řazení v Arrays.sort() nebo různé kolekce založené na binárních vyhledávacích stromech - TreeSet (množina), TreeMap (mapa, slovník), popř. haldě - PriorityQueue (prioritní fronta).
U všech těchto případů použití lze způsob řazení specifikovat i “externě”, a to tzv. komparátorem (viz níže).
package omo4; /* * Porovnavani muzeme resit v nadtride, protoze bude vsude * samozrejme stejne. * Diky generikam nemusime implementovat * Comparable (coz vlastne znamena Comparable<Object>) a * tudiz se nemusime starat ruzne krajni pripady, * kdy posleme nejaky jiny objekt. */ public abstract class Utvar2D implements Comparable<Utvar2D> { public int compareTo(Utvar2D o){ if (obvod() > o.obvod()) { return 1; } else if (obvod()<o.obvod()){ return -1; } else { return 0; } } public abstract double obvod(); public abstract double obsah(); }
package omo4; public class Obdelnik extends Utvar2D{ protected int x1,y1,x2,y2; public Obdelnik (int x1, int y1, int x2, int y2){ this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public double obvod (){ return (Math.abs(x2-x1) * 2) + (Math.abs(y2-y1) * 2); } public double obsah() { return Math.abs(x2-x1) * Math.abs(y2-y1); } @Override public String toString(){ //desetinna mista nas nezajimaji //String.format je staticka metoda tridy string pro snadne formatovani. return String.format( "<Obdelnik[x1=(%d,%d);x2=(%d,%d);o=%.0f;S=%.0f]>", x1,y1,x2,y2,obvod(),obsah()); } }
package omo4; public class Kruh extends Utvar2D{ int x; int y; int r; public Kruh (int x, int y, int r) { this.x = x; this.y = y; this.r = r; } public double obvod(){ return 2 * Math.PI * r; } public double obsah() { return Math.PI * r * r; } @Override public String toString(){ //desetinna mista nas nezajimaji return String.format( "<Kruh[x=(%d,%d);r=%d;o=%.0f;S=%.0f]>", x,y,r,obvod(),obsah()); } }
Interface Comparator umožňuje specifikovat pravidla pro řazení objektů “externě”, bez zásahu do kódu jednotlivých objektů. Navíc, můžeme tak za běhu programu tyto pravidla vyměňovat jen podstrčením jiného objektu komparátoru.
Interface předepisuje jen jedinou metodu compare, má stejné chování jako compareTo, jen jsou oba porovnávané objekty předány pomocí argumentů metody.
Komparátor pak předáme metodě Arrays.sort, popřípadě konstruktoru kolekcí, které jej podporují.
package omo4; import java.util.Comparator; /** * Komparator pro porovnani rovinnych objektu podle obsahu. * Asi je lepsi pouzit generik, trideni jinych objektu naz nezajima * a nemusime se obtezovat resenim pripadu, kdy prijde neco jineho * nez geometricky utvar. */ public class ObsahComparator implements Comparator<Utvar2D>{ public int compare(Utvar2D o1, Utvar2D o2) { if (o1.obsah() > o2.obsah()) { return 1; } else if (o1.obsah()<o2.obsah()){ return -1; } else { return 0; } } }
package omo4; import java.util.Arrays; public class Main { public static void vypisPole(Object[] pole){ for (Object utvar: pole){ System.out.print(utvar+", "); } System.out.println(""); } public static void main (String [] args){ Utvar2D [] pole = new Utvar2D[4]; pole[0] = new Kruh (0,0,10); pole[1] = new Obdelnik(0, 0, 19, 14); pole[2] = new Kruh (0,10,11); pole[3] = new Obdelnik(0, 10, 19, 14); vypisPole(pole); /* * radime podle metod compareTo() * tj. podle obvodu */ Arrays.sort(pole); vypisPole(pole); /* * radime pomoci vlastniho komparatoru * tj. podle obsahu */ Arrays.sort(pole, new ObsahComparator()); vypisPole(pole); } }