Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Excerpt

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

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

Comparable<T>

Comparable er det vanlig at klassen din implementererment å blir implementert av klassen som holder dataene som skal rangeres/sammenlignes. Den krever at du har definert metoden . compareTo(T), hvor T er klassen som skal sammenlignes. CompareTo compareTo-metoden skal returnere et Negativt negativt tall hvis "this" er regnes som mindre enn det andre instanse. argumentet (instans av samme klasse), 0 hvis de er regnes som like, og et positivt tall dersom "this" regnes som er større enn det andre instansetargumentet.

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 medaljerangeringen trenger man en metode for å avgjøre dette.

Code Block
languagejava
titleOlympicCountry
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;
	}

	
// gettere
	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 guldgull 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 guldgull 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 med objekter som implementerer Comparable-interfacetgrensesnittet.

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

Code Block
languagejava
public static void main(String[] args) {

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

Arrays.asList(
			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)
		));		

		printSystem.out.println(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
		
		5-3-7, Sweden: 2-9-3, Finland: 9-2-1, Russia: 2-9-12, Denmark: 7-1-6, England: 5-2-10, Canada: 5-0-4, USA: 9-2-2]
		Altså usortert, men ettersom OlympicCountry-klassen vår implementerer Comparable kan vi nå sortere instansene slik vi ønsker.
		*/
		Collections.sort(countries);
		printSystem.out.println(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	
		-9-3, Russia: 2-9-12, Canada: 5-0-4, England: 5-2-10, Norway: 5-3-7, Denmark: 7-1-6, Finland: 9-2-1, USA: 9-2-2]
		Nå kan dere se at listen er sortert, men den er fortsatt ikke slik vi ønsker den, selvomselv compartToom klassencompareTo-metoden 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<T>

Problemet over er at sorteringsalgoritmen automatisk sorterer i stigende rekkefølge. En enkel fiks løsning 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 , som i motsetning til Comparable, er Comparator tiltenkt ment å 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 kallet til Collections.sort() kallet. Comparator-interfacet grensesnittet krever at du har implementert metoden compare(o1,o2). Denne fungerer på samme måte har samme logikk for returverdien som compareTo(), men tar en inn to argumenter istedet for at et argument sammenlignes med "this" .

Code Block
languagejava
titleComparator
public class MedalComparerMedalComparator 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(Stringboolean orderdescending) {
		ascending = order.toUpperCase().equals("ASCENDING");
		this.descending = order.toUpperCase().equals("DESCENDING")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,(descending ettersom? omo2 man vil ha rangeringen stigende eller synkende
		if(descending){: o1);
			a = o2;
			OlympicCountry b = o1;
		}
		else{
			a = o1;
			b = o2(descending ? o1 : 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-implementasjon. 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.

Code Block
languagejava
titleUsing Comparator in ArrayList
public static void main(String[] args) {
		
		ArrayList<OlympicCountry>List<OlympicCountry> countries = new ArrayList<OlympicCountry>();
		
		countries.add(Arrays.asList(
			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"true));
		printSystem.out.println(countries);
		/*
		Her printes det nå:
		USA		: g [USA: 9, s: -2-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-2-1, Denmark: 7-1-6, Norway: 5-3-7, England: 5-2-10, Canada: 5-0-4, Russia: 2-9-12, Sweden: 2-9-3]
		*/
 
}

...

Det anbefales og å lese dokumentasjonen som er linket til i innledningen for å forstå hvordan java 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