Tässä luvussa tutustutaan String-luokkaan ja sen tarjoamiin metodeihin sekä merkkityyppiin char. Ne ovat sinänsäkin hyödyllisiä, mutta ne myös havainnollistavat sitä, miten Java-kielen valmiit välineet on toteutettu luokkina, ja miten ohjelmoija voi ajatella (ja joutuu ajattelemaan!) olioita luokkien ilmentyminä ja operaatioita luokkien metodeina.
Kun kirjoitetaan:
String jono;määritellään muuttuja jono, jonka arvoksi voidaan sijoittaa String-tyyppisiä olioita. (Metodin muuttujana jonolla ei ole mitään alkuarvoa, luokan muuttujana alkuarvo on null, erityinen viite "ei-mihinkään-olioon".)
Ilmaus:
"kissa"puolestaan tarkoittaa, että luodaan eli konstruoidaan yksi String-tyyppinen olio. Yleensähän oliot luodaan operaatiolla new. Merkintä "kissa" onkin tavallaan vain lyhennysmerkintä ilmaukselle:
new String("kissa")Luokassa String on siis mm. konstruktori, jonka parametri on String-tyyppiä!
Määrittely:
String jono = "topi"+"katti";tarkoittaa yksityiskohtaisesti, että määritellään String-tyyppinen muuttuja jono. Sen alkuarvoksi asetetaan String-olio, joka saadaan, kun ensin luodaan String-oliot "topi" ja "katti" ja sitten nämä katenoimalla luodaan String-olio "topikatti".
Luokka String tarjoaa joukon operaatioita, metodeja, String-arvojen käsittelyyn. Nämä metodit siis ovat String-olioiden aksessoreita ihan samaan tapaan kuin omiin luokkiin on ohjelmoitu aksessoreita.
Omien tyyppien tapaan myös String voidaan nähdä abstraktina tietotyyppinä: Luokan ilmentymän käyttäjä ei tiedä, missä merkkijono sijaitsee ja miten se esitetään muistissa, mutta hän tietää joukon välineitä, joilla arvoja voi käsitellä.
Merkkiarvot (tyyppi char) ovat positiivisia kahden tavun mittaisia kokonaislukuja(!). Merkkivakiot esitetään yksinkertaisissa lainausmerkeissä : 'A', 'k', ' ', '@', ...
[Merkkivakioden ns. heksadesimaaliesitys on muotoa \uXXXX, missä X on heksadesimaaliluku 0-f.]
Merkkiarvon sijoittaminen int-muuttujalle on luvallista, päinvastainen on kiellettyä:
int i = 7; char c = '#'; ... i = c; // SALLITTU, i saa arvokseen merkkikoodin! c = i; // KIELLETTY! (tietoa voisi kadota! (char on intiä suppeampi))Ohjelmanpätkä
char c = '#'; int i = c; // System.out.println("merkkinä: " + c); System.out.println("lukuna : " + i);tulostaa:
merkkinä: # lukuna : 35[int-arvoja voidaan muuttaa ns. eksplisiittisellä tyyppimuunnoksella eli "castilla" char-arvoiksi. Jos tietoa tällöin katoaa, asia on ohjelmoijan vastuulla! Esimerkiksi:
for (int i=40; i<110; ++i) System.out.print( (char)i );tulostaa rivin:
()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm]
Merkkiarvo koodataan ns. Unicode-koodilla, joka sisältää maailman useimpien kirjoitusjärjestelmien kirjain- ja numeromerkit: mm. kreikka, kopti, venäjä, heprea, arabia, devanagari, bengali, gurmukhi, gujarati, tamili, telegu, tai, lao, hiragana, katakana, ...
String jono = "kissa"; int pituus = jono.length(); // pituus = 5;
Esimerkkiohjelma (Rivinpituus.java) tulostaa tulostaa syöttörivin pituuden merkkeinä:
import java.util.Scanner; public class Rivinpituus { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { System.out.println("Kirjoita rivi!"); String jono = lukija.nextLine(); int pituus = jono.length(); System.out.println("Sen pituus on "+pituus); } }
Esimerkkiohjelma Jatkoa1.java suoritetaan uudelleen, jos käyttäjä vastaa jatkamiskysymykseen "kyllä":
import java.util.Scanner; public class Jatkoa1 { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { String vastaus; do { System.out.println("\nNyt ohjelma tekee jotakin hyödyllistä...\n"); System.out.println("Haluatko jatkaa? (kyllä tai ei)"); vastaus = lukija.nextLine(); } while (vastaus.equals("kyllä")); } }Esimerkkiohjelma Jatkoa2.java loppuu, jos käyttäjä vastaa jatkamiskysymykseen "ei":
import java.util.Scanner; public class Jatkoa2 { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { String vastaus; do { System.out.println("\nNyt ohjelma tekee jotakin hyödyllistä...\n"); System.out.println("Haluatko jatkaa? (kyllä tai ei)"); vastaus = lukija.nextLine(); } while (!vastaus.equals("ei")); } }
Esimerkki (Jatkoa3.java):
import java.util.Scanner; public class Jatkoa3 { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { String vastaus; do { System.out.println("\nNyt ohjelma tekee jotakin hyödyllistä...\n"); System.out.println("Haluatko jatkaa? (kyllä tai ei)"); vastaus = lukija.nextLine(); } while (vastaus.equalsIgnoreCase("kyllä")); } }
Esimerkkiohjelma kahden syöttömerkkijonon vertaamiseen (JonoVertailu.java):
import java.util.Scanner; public class JonoVertailu { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { String vastaus; do { System.out.print("Anna ensimmäinen merkkijono: "); String eka = lukija.nextLine(); System.out.print("Anna toinen merkkijono : "); String toka = lukija.nextLine(); int jarjKoodi = eka.compareTo(toka); if (jarjKoodi < 0) System.out.println("Ensimmäinen on ennen toista."); else if (jarjKoodi == 0) System.out.println("Jonot ovat samat."); else // jarjKoodi > 0 System.out.println("Toinen on ennen ensimmäistä."); System.out.println("\nHaluatko jatkaa? (enter jatkaa, kaikki muu lopettaa)"); vastaus = lukija.nextLine(); } while (vastaus.equals("")); } }
String jono = "kissa"; for (int i=0; i<jono.length(); ++i) System.out.println(jono.charAt(i));tulostavat:
k i s s a
String jono = "kissa"; System.out.println(jono.indexOf('s')); // tulostus: 2 System.out.println(jono.indexOf('t')); // tulostus: -1
Huom: indexOf(String str)-versio on aika voimakas ja käyttökelpoinen! Esimerkki (Kissako.java):
... System.out.println("Syötä rivi. Etsin siltä kissaa."); String syöttorivi = lukija.nextLine();; if (syöttorivi.indexOf("kissa") != -1) System.out.println("Jossakin kohdassa syöttörivillä on kissa!"); else System.out.println("Rivi on kissaton."); ...
String jono = "abcd123efg"; String osajono = jono.substring(4,7); System.out.println(osajono); // tulostus 123
String jono = "Onko Matti kukkarossasi?"; System.out.println(jono.toLowerCase()); // tulostus: onko matti kukkarossasi? System.out.println(jono.toUpperCase()); // tulostus: ONKO MATTI KUKKAROSSASI?Huom: Olion, johon operaatio kohdistetaan, ei välttämättä tarvitse olla muuttujan arvona. Myös merkkijonovakiolle voidaan soveltaa String-aksessoreita:
System.out.println("Onko Matti kukkarossasi?".toLowerCase());Ohjelmointitekniikkaa: Tähän ominaisuuteen perustuen on näppärä ohjelmoida välineitä, jotka tutkivat, kuuluuko jokin merkki johonkin merkkijoukkoon. Esimerkiksi vokaalitesti voitaisiin ohjelmoida "pääohjelman pikku apulaisena" seuraavasti:
private static boolean onVokaali(char merkki) { return ("aeiouyåäöAEIOUYÅÄÖ".indexOf(merkki) != -1); }Välinettä voi käyttää vaikkapa seuraavaan tapaan (Vokaalit.java):
System.out.println("Syötä rivi. Tutkin vokaalien määrän."); String rivi = lukija.nextLine(); int vokaaleja = 0; for (int i=0; i<rivi.length(); ++i) if (onVokaali(rivi.charAt(i))) vokaaleja = vokaaleja + 1; System.out.println("Rivillä oli " + vokaaleja + " vokaalia.");
String jono = " Olipa kerran ... "; System.out.println("*" + jono + "*"); System.out.println("*" + jono.trim() + "*");tulostaa:
* Olipa kerran ... * *Olipa kerran ...*
Huom: Kerran luotua String-oliota ei voi muuttaa, koska luokassa String ei ole ainuttakaan operaatiota String-arvon muuttamiseen. Juuri tällä tavoin - Javan kapselointia käyttäen - luokan String ohjelmoija on toteuttanut päätöksensä, etteivät String-oliot ole muutettavissa!
Kaikki edellä luetellut String-arvoiset metodit luovat aina uuden olion! Merkkijonojen muokkaamiseen käytetään muita välineitä. Niistä myöhemmin.
Kun suoritetaan vaikkapa lauseet
String jono = "kissa"; // (1)
jono = jono + " kävelee"; // (2)
luodaan ensin olio "kissa"(1). Sitten luodaan olio " kävelee" ja
lopuksi katenoiden olio "kissa kävelee" (2). Koska muuttujan
jono vanha arvo korvataan uudella, oliosta "kissa" tulee
roska eli siihen ei ole enää viitettä. Samoin " kävelee"-oliolla
oli hyvin hetkellinen merkitys. Automaattinen roskienkerääjä
aikanaan vapauttaa "kissa"- ja " kävelee"-olioiden varaaman muistialueen
muuhun käyttöön.