Olio muodostuu kahdesta asiasta:
Tähän mennessä olemme jo käyttäneet kahdenlaisia olioita:
String-oliot
String
-olion tietosisältönä ovat merkkijonossa olevat merkit.
Olion metodeja ovat mm. length
, joka palauttaa merkkien määrän,
sekä charAt
, joka palauttaa tietyssä kohdassa olevan merkin.
ArrayList-oliot
ArrayList
-olion tietosisältönä ovat listalla olevat arvot.
Olion metodeja ovat mm. add
, joka lisää uuden arvon listalle, sekä
size
, joka palauttaa listalla olevien arvojen määrän.
Luokka kertoo, miten sitä vastaavat oliot rakentuvat. Tarkastellaan esimerkiksi seuraavia merkkijonoja:
"abc"
"testi"
"Java"
Merkkijonot ovat erilaisia, mutta niissä on yhteistä se, että kaikissa on
joukko merkkejä peräkkäin. String
-luokka määrittelee tämän asian:
jokainen String
-olio sisältää joukon merkkejä peräkkäin.
Javassa muuttujan tyyppi on joko alkeistyyppi tai viittaustyyppi.
Alkeistyyppi tarkoittaa, että muuttujaan tallennetaan suoraan sen
arvo. Esimerkiksi int
ja double
ovat
alkeistyyppejä.
Viittaustyyppi tarkoittaa, että muuttujaan tallennetaan viittaus olioon. Luokkaa vastaava muuttuja on viittaustyyppinen.
Tarkastellaan seuraavaa koodia:
String nimi = "Aapeli"; int ika = 31;
Tässä String
on viittaustyyppi, kun taas int
on
alkeistyyppi, minkä vuoksi tilanne muistissa näyttää seuraavalta:
Seuraava koodi havainnollistaa arvon ja viittauksen eroa:
int luku1 = 5; int luku2 = 12; ArrayList<Integer> lista1 = new ArrayList<Integer>(); lista1.add(2); lista1.add(7); ArrayList<Integer> lista2 = new ArrayList<Integer>(); lista2.add(4); System.out.println("luku1 = " + luku1 + ", luku2 = " + luku2); System.out.println("lista1 = " + lista1 + ", lista2 = " + lista2); luku1 = luku2; lista1 = lista2; System.out.println(); System.out.println("luku1 = " + luku1 + ", luku2 = " + luku2); System.out.println("lista1 = " + lista1 + ", lista2 = " + lista2); luku1 = 8; lista2.add(5); System.out.println(); System.out.println("luku1 = " + luku1 + ", luku2 = " + luku2); System.out.println("lista1 = " + lista1 + ", lista2 = " + lista2);
Koodin tulostus on seuraava:
luku1 = 5, luku2 = 12 lista1 = [2, 7], lista2 = [4] luku1 = 12, luku2 = 12 lista1 = [4], lista2 = [4] luku1 = 8, luku2 = 12 lista1 = [4, 5], lista2 = [4, 5]
Seuraava kuva vastaa ensimmäistä tilannetta:
Toisessa tilanteessa tapahtuu seuraavaa:
Nyt muuttujilla luku1
ja luku2
on sama arvo, kun
taas muuttujat lista1
ja lista2
alkavat viitata samaan
olioon.
Kolmas tilanne on mielenkiintoisin:
Muuttujat lista1
ja lista2
viittaavat samaan
olioon, joten kun olio muuttuu, muutos heijastuu kumpaankin muuttujaan.
Yllä olevissa kuvissa kannattaa myös huomata, että vaikka mikään muuttuja ei
viittaa enää listaan [2, 7]
, se on silti edelleen muistissa.
Roskienkerääjä on Javan suoritusympäristön osa, jonka tehtävänä on poistaa muistista tarpeettomia olioita. Se ei välttämättä käy toimeen heti, kun viimeinen viittaus olioon katoaa, mutta ennemmin tai myöhemmin olion varaama tila vapautuu uuteen käyttöön.
Arvon ja viittauksen ero näkyy myös metodin parametreissa. Jos parametri on alkeistyyppinen, metodin muutokset siihen eivät välity kutsukohtaan. Jos taas parametri viittaa olioon ja metodi muuttaa oliota, muutos jää voimaan metodin suorituksen jälkeen.
Asiaa havainnollistaa seuraava metodi:
public static void testi(int luku, ArrayList<Integer> lista) { luku = 5; lista.add(8); }
Käytetään metodia seuraavasti:
int luku = 3; ArrayList<Integer> lista = new ArrayList<Integer>(); lista.add(4); lista.add(7); System.out.println("luku = " + luku + ", lista = " + lista); testi(luku, lista); System.out.println("luku = " + luku + ", lista = " + lista);
Koodin tulostus on seuraava:
luku = 3, lista = [4, 7] luku = 3, lista = [4, 7, 8]
Vaikka metodi asetti parametrille luku
uuden arvon 5,
kutsukohdassa arvo 3 säilyy ennallaan. Sen sijaan luku 8, jonka metodi lisää
parametrin lista
viittaamaan listaan, ilmestyy myös
kutsukohtaan.
Javassa on myös mahdollista ilmaista, että viittaustyyppinen muuttuja ei
viittaa mihinkään olioon. Tällöin muuttujan arvona on null
.
Olio-ohjelmointi kuuluu pääasiassa Ohjelmoinnin jatkokurssin asioihin. Jo
tässä vaiheessa on kuitenkin paikallaan vilkaista, miltä itse tehty olio
näyttää. Teemme luokan Opiskelija
, jota vastaavat oliot pitävät
sisällään yhden opiskelijan tiedot.
Esimerkin testaamiseksi voit luoda uuden NetBeans-projektin, jonka nimeksi
tulee OpiskelijaTesti
. Saat projektiin uuden luokan valitsemalla
File -> New File ja kirjoittamalla kohtaan Class Name
luokan nimeksi Opiskelija
.
Luokan Opiskelija
koodi on seuraava:
public class Opiskelija { private String nimi; private int opintopisteet; public Opiskelija(String nimi, int opintopisteet) { this.nimi = nimi; this.opintopisteet = opintopisteet; } public void opiskele() { opintopisteet++; } public String toString() { return nimi + " (" + opintopisteet + " op)"; } }
Seuraava ohjelma esittelee luokan käyttöä:
public class OpiskelijaTesti { public static void main(String[] args) { Opiskelija aapeli = new Opiskelija("Aapeli", 115); Opiskelija maija = new Opiskelija("Maija", 209); System.out.println("Opiskelijat:"); System.out.println(aapeli); System.out.println(maija); aapeli.opiskele(); aapeli.opiskele(); maija.opiskele(); System.out.println("Opiskelijat:"); System.out.println(aapeli); System.out.println(maija); } }
Ohjelman tulostus on seuraava:
Opiskelijat: Aapeli (115 op) Maija (209 op) Opiskelijat: Aapeli (117 op) Maija (210 op)
Tarkastellaan osissa luokan Opiskelija
rakennetta:
Olion alussa olevat muuttujat vastaavat sen tietosisältöä:
private String nimi; private int opintopisteet;
Tässä olio sisältää opiskelijan nimen ja opintopisteiden määrän.
Olion konstruktori kertoo, mitä tapahtuu olion luonnissa:
public Opiskelija(String nimi, int opintopisteet) { this.nimi = nimi; this.opintopisteet = opintopisteet; }
Tässä olion luonnissa annetut opiskelijan nimi ja opiskelijanumero tallennetaan sellaisenaan olion muuttujiin.
Metodin opiskele
avulla voi suurentaa opintopistemäärää:
public void opiskele() { opintopisteet++; }
Metodi toString
kertoo, millaisen merkkijonoesityksen olio antaa
itsestään esimerkiksi tulostuskomennossa:
public String toString() { return nimi + " (" + opintopisteet + " op)"; }
Tässä merkkijonoesitys on muotoa "X (Y op)", jossa X on opiskelijan nimi ja Y on opintopisteiden määrä.
Tässä vaiheessa riittää, että saat suoritettua esimerkin ja ymmärrät suurin piirtein, mitä siinä tapahtuu. Palaamme asiaan tarkemmin Ohjelmoinnin jatkokurssilla.