Rajapinta vaatii, että luokka sisältää tietyt metodit. Rajapintojen avulla samalla koodilla voidaan käsitellä erityyppisiä olioita, joissa on kuitenkin yhteisiä piirteitä.
Rajapinta määritellään muuten samalla tavalla kuin luokka, mutta sanan
class
tilalla on sana interface
ja rajapinnan ainoa
sisältö on joukko metodien runkoja.
Seuraava rajapinta Puhuva
vaatii, että luokassa on metodi
puhu
:
public interface Puhuva { public void puhu(); }
Luokat Koira
, Kissa
ja Lehma
toteuttavat rajapinnan Puhuva
:
public class Koira implements Puhuva { public void puhu() { System.out.println("Hau hau!"); } }
public class Kissa implements Puhuva { public void puhu() { System.out.println("Miau!"); } }
public class Lehma implements Puhuva { public void puhu() { System.out.println("Ammuu!"); } }
Seuraava koodi esittelee luokkien käyttämistä:
ArrayList<Puhuva> elaimet = new ArrayList<Puhuva>(); elaimet.add(new Koira()); elaimet.add(new Kissa()); elaimet.add(new Lehma()); for (Puhuva elain : elaimet) { elain.puhu(); }
Ohjelman tulostus on seuraava:
Hau hau! Miau! Ammuu!
Tässä rajapinta Puhuva
takaa, että kaikki rajapinnan
toteuttavat luokat sisältävät metodin puhu
. Tämän ansiosta
metodia voidaan kutsua kaikille listan olioille, vaikka niiden tarkemmasta
tyypistä ei ole tietoa.
Yksi Javan valmiista rajapinnoista on Comparable
. Tämä
rajapinta vaatii, että luokassa on metodi compareTo
, jolla voi
verrata kahden luokkaa vastaavan olion järjestystä keskenään.
Metodin kutsutapa on a.compareTo(b)
, ja metodin palautusarvon
tulisi olla seuraava:
a
tulee järjestyksessä b
:tä ennen, tulos on
negatiivinen
a
tulee järjestyksessä b
:n jälkeen, tulos on
positiivinen
a
ja b
ovat järjestyksessä samassa kohtaa,
tulos on 0
Luokka String
sisältää valmiiksi metodin
compareTo
. Tässä tapauksessa järjestys tarkoittaa
merkkijonojen aakkosjärjestystä. Seuraava koodi esittelee metodin toimintaa:
String eka = "Aapeli"; String toka = "Maija"; String kolmas = "Aapeli"; System.out.println(eka.compareTo(toka)); System.out.println(toka.compareTo(eka)); System.out.println(eka.compareTo(kolmas));
Koodin tulostus on seuraava:
-12 12 0
Merkkijono "Aapeli" on aakkosissa ennen kuin "Maija", joten ensimmäinen arvo on negatiivinen ja toinen on positiivinen. Tässä ei ole oleellista se, että arvot sattuvat olemaan nimenomaan -12 ja 12, vaan se, että niiden negatiivisuus ja positiivisuus kertovat merkkijonojen järjestyksen.
Metodia compareTo
tarvitaan esimerkiksi silloin, kun listan
sisältö halutaan järjestää. Esimerkiksi seuraava koodi toimii, koska luokkaan
String
on toteutettu metodi compareTo
:
ArrayList<String> nimet = new ArrayList<String>(); nimet.add("Uolevi"); nimet.add("Aapeli"); nimet.add("Maija"); Collections.sort(nimet); System.out.println(nimet);
Koodin tulostus on seuraava:
[Aapeli, Maija, Uolevi]
Jos oman luokan olioita on tarpeen vertailla, metodi compareTo
täytyy toteuttaa itse. Näin luokan saa toteuttamaan rajapinnan
Comparable
, joka on vaatimuksena esimerkiksi metodin
Collections.sort
käyttämiselle.
Seuraavassa esimerkissä luokkaan Henkilo
on lisätty metodi
compareTo
. Tässä järjestys määräytyy ensisijaisesti henkilön
sukunimen ja toissijaisesti henkilön etunimen perusteella.
public class Henkilo implements Comparable<Henkilo> { private String etunimi; private String sukunimi; public Henkilo(String etunimi, String sukunimi) { this.etunimi = etunimi; this.sukunimi = sukunimi; } public String toString() { return etunimi + " " + sukunimi; } public int compareTo(Henkilo toinen) { if (sukunimi.equals(toinen.sukunimi)) { return etunimi.compareTo(toinen.etunimi); } else { return sukunimi.compareTo(toinen.sukunimi); } } }
Luokka hyödyntää merkkijonometodeja equals
ja
compareTo
: jos sukunimet ovat samat, palautetaan etunimien
vertailun tulos, ja muuten palautetaan sukunimien vertailun tulos.
Huomaa, että metodissa compareTo
viitataan toisen olion
yksityisiin muuttujiin. Tämä on mahdollista silloin, kun toisen olion luokka
on sama kuin oman olion luokka.
Nyt henkilöiden lista voidan järjestää seuraavasti:
ArrayList<Henkilo> lista = new ArrayList<Henkilo>(); lista.add(new Henkilo("Roope", "Ankka"); lista.add(new Henkilo("Mikki", "Hiiri"); lista.add(new Henkilo("Aku", "Ankka"); Collections.sort(lista); System.out.println(lista);
Koodin tulostus on seuraava:
[Aku Ankka, Roope Ankka, Mikki Hiiri]
Seuraava rajapinta Alue
vastaa maantieteellistä aluetta:
public interface Alue { public int vakiluku(); public void tulosta(int sisennys); }
Metodi vakiluku
palauttaa alueen asukasmäärän ja metodi
tulosta
tulostaa alueen tiedot halutusti sisennettynä.
Esimerkkiohjelma selventää, mitä sisennys tarkoittaa käytännössä.
Määritellään rajapinnan toteuttavia luokkia:
public class Valtio implements Alue { private String nimi; private int vakiluku; public Valtio(String nimi, int vakiluku) { this.nimi = nimi; this.vakiluku = vakiluku; } public int vakiluku() { return vakiluku; } private void tulostaSisennys(int sisennys) { for (int i = 0; i < sisennys; i++) { System.out.print(" "); } } public void tulosta(int sisennys) { tulostaSisennys(sisennys); System.out.println(nimi + " (" + vakiluku + " asukasta)"); } }
import java.util.*; public class Aluejoukko implements Alue { private String nimi; private ArrayList<Alue> alueet = new ArrayList<Alue>(); public Aluejoukko(String nimi) { this.nimi = nimi; } public void lisaaAlue(Alue alue) { alueet.add(alue); } public int vakiluku() { int tulos = 0; for (Alue alue : alueet) { tulos += alue.vakiluku(); } return tulos; } private void tulostaSisennys(int sisennys) { for (int i = 0; i < sisennys; i++) { System.out.print(" "); } } public void tulosta(int sisennys) { tulostaSisennys(sisennys); System.out.println(nimi); for (Alue alue : alueet) { alue.tulosta(sisennys + 4); } } }
Seuraava ohjelma esittelee luokkien käyttämistä:
Valtio suomi = new Valtio("Suomi", 5300000); Valtio ruotsi = new Valtio("Ruotsi", 9400000); Valtio norja = new Valtio("Norja", 4600000); Valtio tanska = new Valtio("Tanska", 5400000); Valtio viro = new Valtio("Viro", 1200000); Valtio latvia = new Valtio("Latvia", 2200000); Valtio liettua = new Valtio("Liettua", 3500000); Aluejoukko pohjoismaat = new Aluejoukko("Pohjoismaat"); pohjoismaat.lisaaAlue(suomi); pohjoismaat.lisaaAlue(ruotsi); pohjoismaat.lisaaAlue(norja); pohjoismaat.lisaaAlue(tanska); Aluejoukko baltianMaat = new Aluejoukko("Baltian maat"); baltianMaat.lisaaAlue(viro); baltianMaat.lisaaAlue(latvia); baltianMaat.lisaaAlue(liettua); Aluejoukko itamerenMaat = new Aluejoukko("Itämeren maat"); itamerenMaat.lisaaAlue(pohjoismaat); itamerenMaat.lisaaAlue(baltianMaat); System.out.println("Itämeren maiden väkiluku: " + itamerenMaat.vakiluku()); itamerenMaat.tulosta(0);
Ohjelman tulostus on seuraava:
Itämeren maiden väkiluku: 31600000 Itämeren maat Pohjoismaat Suomi (5300000 asukasta) Ruotsi (9400000 asukasta) Norja (4600000 asukasta) Tanska (5400000 asukasta) Baltian maat Viro (1200000 asukasta) Latvia (2200000 asukasta) Liettua (3500000 asukasta)
Tässä aluejoukko voi muodostua toisista aluejoukoista, mikä mahdollistaa puumaisen rakenteen toteuttamisen.