You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Denne siden forklarer hvordan grensesnittene java.util.Comparable og java.util.Comparator bidrar til sortering i Java.

Comparable og Comparator er interfaces som lar deg bestemme hvordan dine egne objekter skal rangeres i forhold til hverandre. Dette kommer spesielt godt til nytte når man bruker Collection-rammeverket, spesielt metoden Collections.sort. Disse interfacene krever en metode hver, henholds vis Compare(T o1, T o2) og compareTo(T o) hvor T er klassen som skal sammenlignes.

Comparable<T>

Comparable er det vanlig at klassen din implementerer. Den krever at du har definert metoden .compareTo(T), hvor T er klassen som skal sammenlignes. CompareTo metoden skal returnere et Negativt tall hvis "this" er mindre enn det andre instanse. 0 hvis de er like, og et positivt tall dersom "this" er større enn det andre instanset.

Sett at du har en klasse som definerer et Land som deltar i OL. Klassen har felter for antall gull, sølv og bronsje. For at du skal kunne avgjøre hvilket land som kommer høyest opp på medalje rangeringen trenger man en metode for å avgjøre dette.

OlympicCountry
public class OlympicCountry implements Comparable<OlympicCountry> { //inne i klammene defineres hvilken klasse som skal sammenlignes i compareTo-metoden

	private String name;
	private int goldMedals;
	private int silverMedals;
	private int bronzeMedals;

	public OlympicCountry(String name, int goldMedals, int silverMedals, int bronzeMedals){

		this.name = name;
		this.goldMedals = goldMedals;
		this.silverMedals = silverMedals;
		this.bronzeMedals = bronzeMedals;
	}

	

	public int getGoldMedals() {
		return goldMedals;
	}
	public int getSilverMedals() {
		return silverMedals;
	}
	public int getBronzeMedals() {
		return bronzeMedals;
	}

	@Override
	public String toString(){
		return name + "\t: g: "+ goldMedals+", s: " + silverMedals + ", b: " + bronzeMedals;
	}

	//@Override
	public int compareTo(OlympicCountry o) {
		if(this.getGoldMedals() != o.getGoldMedals()) // hvis guld er ulike returnerer deres forskjell
			return this.getGoldMedals() - o.getGoldMedals();
		else if(this.getSilverMedals() != o.getSilverMedals())//hvis sølv er ulike returneres deres forskjell
			return this.getSilverMedals() - o.getSilverMedals();
		else
			return this.getBronzeMedals() - o.getBronzeMedals(); // hvis den er kommet hit er guld og sølv like, da returnerer den bronsje forskjellen. Om den også er lik returneres 0, som indikerer at instansene er like gode.
	}

	

	public static void main(String[] args) {
		OlympicCountry china = new OlympicCountry("China", 2, 4, 1);
		OlympicCountry japan = new OlympicCountry("Japan", 2, 5, 1);

		System.out.println(china.compareTo(Japan)); // printer ut -1. Dette betyr at Japan er bedre enn Kina.
	}

Så hvorfor er dette så fantastisk. Jo, som nevnt over så kan man bruke det i forbindelse med sortering. Collections.sort() krever bare at du sender med en liste som arver fra Collections og at denne listen inneholder et objekt som implementerer Comparable-interfacet.

Her ser dere en ny main-metode som bruker den allerede definerte klassen over OlympicCountry

public static void main(String[] args) {

		ArrayList<OlympicCountry> countries = new ArrayList<OlympicCountry>();

		countries.add(new OlympicCountry("Norway", 5, 3, 7));
		countries.add(new OlympicCountry("Sweden", 2, 9, 3));
		countries.add(new OlympicCountry("Finland", 9, 2, 1));
		countries.add(new OlympicCountry("Russia", 2, 9, 12));
		countries.add(new OlympicCountry("Denmark", 7, 1, 6));
		countries.add(new OlympicCountry("England", 5, 2, 10));
		countries.add(new OlympicCountry("Canada", 5, 0, 4));
		countries.add(new OlympicCountry("USA", 9, 2, 2));		

		print(countries);
		/*
		Printer ut:
		Norway	: g: 5, s: 3, b: 7
		Sweden	: g: 2, s: 9, b: 3
		Finland	: g: 9, s: 2, b: 1
		Russia	: g: 2, s: 9, b: 12
		Denmark	: g: 7, s: 1, b: 6
		England	: g: 5, s: 2, b: 10
		Canada	: g: 5, s: 0, b: 4
		USA		: g: 9, s: 2, b: 2
		
		Altså usortert, men ettersom klassen vår implementerer Comparable kan vi nå sortere instansene slik vi ønsker.
	*/
		Collections.sort(countries);
		print(countries);
		/*
		Sweden	: g: 2, s: 9, b: 3
		Russia	: g: 2, s: 9, b: 12
		Canada	: g: 5, s: 0, b: 4
		England	: g: 5, s: 2, b: 10
		Norway	: g: 5, s: 3, b: 7
		Denmark	: g: 7, s: 1, b: 6
		Finland	: g: 9, s: 2, b: 1
		USA		: g: 9, s: 2, b: 2	
		
		Nå kan dere se at listen er sortert, men den er fortsatt ikke slik vi ønsker den, selvom compartTo klassen er helt rett. Les neste avsnitt for løsningen.
	}


	//for oversiktelig utskrift av ArrayListen
	public static void print(ArrayList<OlympicCountry> countries){
		for (OlympicCountry country : countries) {
			System.out.println(country);
		}
	}

 

Comparator

Problemet over er at sorteringsalgoritmen automatisk sorterer i stigende rekkefølge. En enkel fiks ville vært å bytte om på objektene i compareTo()-metoden, men dette ville vært feil ettersom Comparable skal gjenspeile klassens naturlige ordning, og kan derfor ikke tilpasses for et spesielt problem. Løsningen er å bruke en Comparator. I motsetning til Comparable , så er Comparator tiltenkt å implementeres av en annen klasse enn den som skal sorteres. Den kan da også ha friere regler på utfallet av sammenligninger. For å bruke en Comparator sendes den enkelt med som et andre argument til Collections.sort() kallet. Comparator-interfacet krever at du har metoden compare(o1,o2). Denne fungerer på samme måte som compareTo(), men tar en inn to argumenter istedet for at et argument sammenlignes med "this"

 

Comparator
public class MedalComparer implements Comparator<OlympicCountry>{ //spesifiser hvilken klasse som skal sammenlignes som vanlig
	
	private boolean ascending;
	private boolean descending;
	
	//laget en custom constructor hvor du kan bestemme om du vil rangere stigende eller synkende
	public MedalComparer(String order){
		ascending = order.toUpperCase().equals("ASCENDING");
		descending = order.toUpperCase().equals("DESCENDING");
	}
	//her sammenlignes to eksterne instanser med hverandre
	@Override
	public int compare(OlympicCountry o1, OlympicCountry o2) {
		OlympicCountry a;
		OlympicCountry b;
		
		//denne if-løkken tilegner objektene til a eller b, ettersom om man vil ha rangeringen stigende eller synkende
		if(descending){
			a = o2;
			b = o1;
		}
		else{
			a = o1;
			b = o2;
		}
		//denne delen er helt lik som compareTo() metoden, a tilsvarer "this" og b tilsvarer "other"
		if(a.getGoldMedals() != b.getGoldMedals())
			return a.getGoldMedals() - b.getGoldMedals();
		else if(a.getSilverMedals() != b.getSilverMedals())
			return a.getSilverMedals() - b.getSilverMedals();
		else
			return a.getBronzeMedals() - b.getBronzeMedals();
	}
}

Ovenfor ser du hvordan en enkel Comparator klasse. Under kan du se hvordan den brukes i en main-metode, som også har referanser til den allerede definerte OlympicCountry-klassen og print metoden, som du finner litt lenger oppe.

Using Comparator in ArrayList
public static void main(String[] args) {
		
		ArrayList<OlympicCountry> countries = new ArrayList<OlympicCountry>();
		
		countries.add(new OlympicCountry("Norway", 5, 3, 7));
		countries.add(new OlympicCountry("Sweden", 2, 9, 3));
		countries.add(new OlympicCountry("Finland", 9, 2, 1));
		countries.add(new OlympicCountry("Russia", 2, 9, 12));
		countries.add(new OlympicCountry("Denmark", 7, 1, 6));
		countries.add(new OlympicCountry("England", 5, 2, 10));
		countries.add(new OlympicCountry("Canada", 5, 0, 4));
		countries.add(new OlympicCountry("USA", 9, 2, 2));
		
		Collections.sort(countries,new MedalComparer("descending"));
		print(countries);
		/*
		Her printes det nå:
		USA		: g: 9, s: 2, b: 2
		Finland	: g: 9, s: 2, b: 1
		Denmark	: g: 7, s: 1, b: 6
		Norway	: g: 5, s: 3, b: 7
		England	: g: 5, s: 2, b: 10
		Canada	: g: 5, s: 0, b: 4
		Russia	: g: 2, s: 9, b: 12
		Sweden	: g: 2, s: 9, b: 3
		*/
 
}

 

Det anbefales og lese dokumentasjonen som er linket i innledningen for å forstå hvordan java forventer at metodene skal fungere. Forskjellen er ikke så stor. Er du i tvil om hva du skal bruke vil det i de fleste tilfeller fungere og la klassen som skal sorteres implementere Comparable().

 

 

SidetypeFerdig
Teori90

 

 

 

  • No labels