720 likes | 931 Views
Java-perusteet. Kari Kujansuu 26.2.2004. Sisältö. Java-ohjelmoinnin perusteet kääntäminen, ajaminen, JAR-tiedostot, classpath Java-kielen syntaksia olio-ohjelmointia dokumentaatio luokkakirjasto JDBC yleisiä huomautuksia Tandem-ympäristö. Java-ohjelman perusrakenne:.
E N D
Java-perusteet Kari Kujansuu 26.2.2004
Sisältö • Java-ohjelmoinnin perusteet • kääntäminen, ajaminen, JAR-tiedostot, classpath • Java-kielen syntaksia • olio-ohjelmointia • dokumentaatio • luokkakirjasto • JDBC • yleisiä huomautuksia • Tandem-ympäristö
Java-ohjelman perusrakenne: • Java-ohjelma koostuu yhdestä tai useammasta luokasta (class): • Demo.java: class Demo{ String a; public static void main(String[] args) { // koodia ... } int func1() { } /* lisää metodeja... */}
Käännös: • javac Demo.java • luo tiedoston Demo.class • Ohjelman ajaminen: • java Demo param1 param2 ... • käynnistää metodin "main" niin että args-taulukossa on annetut parametrit • args[0] <- param1 • args[1] <- param2 • ...
Huomautuksia: • Syntyneen luokan (class) nimi on Demo • Syntyneen luokkatiedoston nimi on Demo.class • Luokan ja luokkatiedoston nimi tulee class-määrityksestä, ei Demo.java-tiedoston nimestä • Yhdessä .java-tiedostossa voi olla monta luokkaa (class); jokaisesta tulee oma luokkatiedosto, mutta tämä ei ole suositeltua (yleensä luokka per tiedosto) • Todellisessa tapauksessa käytetään: • pakkauksia (package), jolloin luokkatiedostot sijoittuvat omiin hakemistoihinsa • jar-tiedostoja, jolloin luokat lisäksi pakataan yhteen tiedostoon
Laajennettu esimerkki: • Demo.java: package com.hp.kku; class Demo{ public static void main(String[] args) { } int func1() { }} • Demo2.java: package com.hp.kku;class Demo2{ void func2() { }}
Käännös: • javac -d classes *.java • Luo tiedostot • classes/com/hp/kku/Demo.class • classes/com/hp/kku/Demo2.class • Syntyneiden luokkien nimet sisältävät pakkauksen nimen: • com.hp.kku.Demo • com.hp.kku.Demo2 • Ohjelman ajaminen: java -classpath classes com.hp.kku.Demo param1 param2
Huomautuksia: • Demo2-luokka ei sisällä main-metodia, se on apuluokka jota Demo todennäköisesti käyttää • Suositus package-nimille on yrityksen Internet-domain-nimi (käänteisenä) + yksikäsitteinen sovelluksen tms. nimi. • java-tulkkia sanotaan myös JVM:ksi (Java Virtual Machine)
JAR-tiedostojen käyttö • Tyypillisessä sovelluksessa on suuri määrä luokkia (ja luokkatiedostoja). Näiden käsitellyn helpottamiseksi ne voidaan pakata yhteen tiedostoon jar-ohjelmalla: cd classes jar -cvf Demo.jar * • Paketoi hakemiston "classes" (alihakemistoineen) jar-tiedostoon Demo.jar • Nyt classes-hakemiston voi tuhota ja ohjelmaa voi ajaa • java -classpath Demo.jar com.hp.kku.Demo param1 param2 ... • JAR-tiedosto in itse asiassa ZIP-formaatissa, joten sitä voi lukea esim. WinZIP-ohjelmalla.
CLASSPATH • Classpath-kertoo ne hakemistot tai jar/zip-tiedostot, joista luokkia (so. class-tiedostoja) etsitään • Classpath voidaan asettaa myös ympäristömuuttujana, esim. • export CLASSPATH=.:classes:/home/lib/util.jar • Esimerkki • CLASSPATH=.:classes:/home/lib.jar • haettava luokka on com.hp.kku.Demo2 • JVM etsii tiedostoja (tässä järjestyksessä): • ./com/hp/kku/Demo2.class • classes/com/hp/kku/Demo2.class • /com/hp/kku/Demo2.jar (lib.jar-tiedoston sisältä)
CLASSPATH • Luokat voi kääntää erikseen, kääntäjä hakee automaattisesti aikaisemmin käännetyt luokat CLASSPATHia käyttäen • tämän takia myös käännöskomennossa (javac) tarvitaan yleensä classpath-määritys
Java-kielestä • Perustietotyypit: • int, char, byte, long, float, double • String • Taulukot • int[] luvut = new int[100]; • String[] sanat = new String[sanojen_lukumäärä]; • Isot ja pienet kirjaimet, konventiot: • luokkien nimet alkavat isolla kirjaimella: Demo • muuttujien nimet alkavat pienellä: sanojen_lukumäärä tai sanojenLukumäärä • pakkausten nimet kokonaan pienillä: com.hp.kku • vakiot kokonaan isoilla: MAX_LEN
Java-kielestä • Kaikki muuttujat ja funktiot (metodit) määritellään jonkin luokan sisään, globaaleja muuttujia ei ole • class Demo • { int sanojen_lukumäärä = 50; String[] sanat = new String[sanojen_lukumäärä]; public static void main(String[] args) { } void func1() { } • }
Java-kielestä • ehtolause • if (a == 1 && s.equals(””)){ ...} • silmukka • while (a == 1 && s.equals(””)){ ...} • for-silmukka • for (int i=0; i<10; i++) { ... break; // silmukan ennenaikainen lopetus}
Java-kielestä • lauseet ja määritykset päätetään puolipisteeseen (ei kuitenkaan aaltosulun jälkeen) • a = 1; // sijoituslause • System.out.println(”Hei”); // metodikutsu • func2(); // metodikutsu • obj.func2(); // metodikutsu • return; // paluu metodista • return 0; // paluu ja paluuarvon palautus
Taulukot • int[] numerot = new int[50]; • String[] sanat = new String[100]; • taulukon läpikäynti: for (int i=0;i<sanat.length;i++) { System.out.println(sanat[i]); } • String-taulukon alkiot alustetaan null-arvoilla (samoin kaikki objekti) • JVM tarkistaa kaikki indeksiviittaukset (IndexOutOfBoundsException)
Taulukot • String- tai objekti-taulukon alkiot ovat itse asiassa vain viittauksia. Ne alustetaan null-arvoilla. • Jos halutaan todella luoda n kappaletta olioita, pitää se tehdä itse: Demo[] demot = new Demo[20]; for (int i=0;i<demot.length;i++) demot[i] = new Demo();
Merkkijonot • java.lang.String - ei voi modifioida • java.lang.StringBuffer - sisältöä voi muokata • String s; • String s2 = ”abc”; • String s3 = new String(”abc”); • s = ”abc” + ”def”; // -> ”abcdef” • s = ”abc” + 123; // -> ”abc123” • s.length() - palauttaa merkkijonon pituuden • s.equals(s2) - merkkijonojen vertailu ! • Demo demo1 = new Demo(); • s = ”abc” + demo1; // = ”abc” + demo1.toString(); • s = ”abc\ndef”; • char c = s.charAt(2);
Hello World • class Hello{ public static void main(String[] args) { System.out.println(”Hello there”); • }}
Hello World: huomautuksia • luokan nimi on Hello, source on siis Hello.java, luokkatiedosto Hello.class • System on luokka (itse asiassa java.lang.System), joka sisältää staattisen out-muuttujan tulostusta varten sekä eräitä yleiskäyttöisiä metodeja • out-muuttujan tyyppi on java.lang.PrintStream, se sisältää println-metodin ja muita metodeja tulostusta varten • class System{ • public static PrintStream out;}class PrintStream • { • public void println(String s) { ... } • }
Harjoitukset • Harjoituksissa tsekataan, että tekstieditori ja kääntäjäympäristö ovat kunnossa ja kerrataan java-sovellusten perusominaisuuksia.. • Ota käyttöön verkkolevy \\15.170.15.248\root • Windows Explorer: Tools: Map Network Drive: • Folder: \\15.170.15.248\root • Username: java.user<n>, Password: (tyhjä) • Käynnistä editori PFE32.exe hakemistosta d:\home\PFE • d: on edellisessä kohdassa käyttöön otettu levy • voit myös kopioida ym. hakemiston työasemaasi • Tee tiedostot OSS-hakemistoon /home/java/user<n> (ts. d:\home\java\user<n>) • Talleta tiedostot UNIX-formaatissa (PFE:n statusrivillä on valinta DOS/Unix, jota voi vaihtaa kaksoisklikkauksella) • Ota emulaattoriyhteys osoitteeseen 15.170.15.248, valitse BASH, tunnus java.user<n>, ei salasanaa • Emulation: VT220/VT320, Scroll Buf Size=500, Auto Wrap=On
Harjoitus 1 • 1. Tee sovellus, joka tulostaa oman nimesi. • 2. Tee sovellus, joka tulostaa parametrina saamansa merkkijonon. (args) • 3. Tee sovellus, joka tulostaa kaikki parametrinään saamansa merkkijonot riveittäin ja lisäksi kertoo montako merkkiä jokaisessa merkkijonossa oli ja montako yhteensä. (args.length) • 4. Lisää (johonkin em.) ohjelmaan määritys ”package harj1;” ja kokeile eri vaihtoehtoja: • a) javac Prog.java • b) javac -d . Prog.java • c) javac -d classes Prog.java • Mikä on .class-tiedoston sijainti kussakin tapauksessa? • Millä komennolla ohjelma käynnistyy kussakin tapauksessa? • java ??? • huom. a)-kohdassa ohjelmaa ei voi ajaa! • 5. Talleta ohjelma jar-tiedostoon ja aja sitä sieltä.
Metodeista • class A{ int m(int p) { int x,y; // paikallisia muuttujia ... return 0; }// ylikuormitus; saman niminen metodi eri parametreilla int m(int p,int q) { ... return 0; }}
Luokat ja objektit • Jos perustietotyypit eivät riitä, voidaan koota muuttujia ja metodeja yhteen klönttiin, jota sanotaan luokaksi. Luokka on siis ohjelmoijan määrittelemä uusi "tietotyyppi". • Edelleen voidaan määritellä muuttujia joiden tyyppi on haluttu luokka. Tällainen muuttuja on kuitenkin vain "referenssi" tai "osoitin" joka VOI viitata ko. luokan tyypiseen OBJEKTIIN. Nämä objektit luodaan "new"-operaattorilla: • Demo demo1 = null; • demo1 = new Demo(); • demo1 = new Demo(); • Demo demo2 = new Demo(); • demo2 = demo1;
Luokat ja objektit Demo demo1; demo ei vielä osoita mihinkään objektiin, tässä vaiheessa ei ole olemassa yhtään Demo-tyyppistä objektia demo1 = new Demo(); tässä luodaan yksi Demo-tyyppinen objekti ja samalla asetetaan muuttuja demo viittaamaan siihen demo1 = new Demo(); tässä luodaan TOINEN Demo-tyyppinen objekti ja samalla asetetaan muuttuja demo viittaamaan siihen. Edellinen viittaus "katoaa", ensimmäiseen objektiin ei ole enää yhtään viittausta demo1 Demo demo1 Demo demo1 Demo
Luokat ja objektit Demo demo2 = new Demo();tässä luodaan uusi Demo-tyyppinen objekti demo2 = demo1; viimeksi luotu muuttuja pannaan osoittamaan enimmäiseen olioon. Oliot, joihin ei enää ole viittauksia, muuttuvat ”roskaksi” (garbage), ja JVM vapauttaa niiden käyttämän muistin automaattisesti ”roskien keruussa” (garbage collection) Demo demo1 Demo demo2 Demo demo1 Demo demo2
Luokat ja objektit • demo.func1(); • tässä kutsutaan ko. objektin metodia "func1" • demo.sanojen_lukumäärä = 100; • tässä asetetaan ko. objektin muuttujalle uusi arvo • demo = null; • tämän jälkeen demo ei enää osoita mihinkään olioon
Kapselointi: • sekä data että koodi suljetaan samaan ”kapseliin”, so. luokkaan • muuttujat määritellään yleensä privaateiksi, jolloin niihin pääsee käsiksi vain luokan sisältä ja metodien välityksellä • class A{ private int x = 0; void asetaX(int new_x) { if (new_x > 0) x = new_x; }}
Staattiset muuttujat ja metodit • Normaalisti luokan sisällä määritellyt muuttujat ovat olemassa kunkin olion sisällä: class Demo { int x; } Demo d1 = new Demo(); Demo d2 = new Demo(); • d1.x on eri muuttuja kuin d2.x Demox=1 d1 Demox=2 d2
Staattiset muuttujat ja metodit • static-määreellä määriteltyjä muuttujia on kuitenkin vain yksi per luokka ja siihen voi viitata luokan nimen avulla: • class Demo • { static int y; static final int MAX_LEN = 100; } Demo.y = 1; if (len < Demo.MAX_LEN) ...
Staattiset muuttujat ja metodit • esimerkki staattisesta metodista: factory (tehdas) • factory on staattinen metodi, joka palauttaa halutun tyyppisen olion • class DemoFactory{ public static Demo getDemo() { … return new Demo(…); }} • tätä voisi kutsua: • Demo demo = DemoFactory.getDemo();
Konstruktorit • usein oliota luotaessa halutaan samalla alustaa se tietyllä tavalla • tätä varten luokkaan voidaan määritellä erityinen metodi, konstruktori • konstruktorin nimi on aina sama kuin luokan nimi, sillä ei ole paluuarvoa • class Demo{ public Demo(int a,String nimi) { … }} • nyt olio luodaan esim. • Demo d = new Demo(10,”Kari”);
Konstruktorit • konstruktoreita voi olla monta, erityyppisillä parametreilla • tyypillisesti konstruktori tallettaa parametrinsa objektin muuttujiin: • class Demo{ private String nimi; private int arvo; public Demo(int a,String nimi) { arvo = a; this.nimi = nimi; … }}
Interfacet (rajapinnat) • Interface määrittelee joukon metodikutsuja (nimet, parametrien tyypit, paluutyypit), mutta ei metodien koodia • jokin luokka voi sitten toteuttaa ko. rajapinnan, ts. ko. luokassa on toteutus jokaiselle rajapinnan metodille • interface Interfacename{ int methodname(args…);}class Classname implements Interfacename{ public int methodname(args…) { … } // muita metodeja}
Interfacet • kuvitteellinen esimerkki: • interface SQLOperations{ void executeStatement(String sqlstatement); …}class SQLMPDriver implements SQLOperations{ public void executeStatement(String sqlstatement) { … } …}class SQLMXDriver implements SQLOperations{ public void executeStatement(String sqlstatement) { … } …}
Interfacet • luokka voi toteuttaa useita rajapintoja • class A implements X, Y{…} • rajapinta voi olla metodin (muodollisena) parametrina: • void metodi(X param){} • silloin mikä tahansa luokka, joka toteuttaa ko. rajapinnan, voidaan välittää todellisena parametrina: • A a = new A();metodi(a); • myös metodin paluuarvo voi olla rajapinnan nim. Silloin metodi palauttaa todellisuudessa viittauksen johonkin luokkaan, joka toteuttaa ko. rajapinnan. Kutsuvan ohjelman ei tarvitse tietää mikä luokka on kyseessä • hyviä esimerkkejä: java.util.*, JDBC
Interfacet • interface kääntyy myös .class-tiedostoksi
Harjoitus 2 - rajapinnat • Tee seuraavat luokat • class Demo • main • interface DemoInt • void show(); • class Demo2 implements DemoInt • Demo2(int i) { ... } • public void show() { ... } • Kaikki luokat voi tehdä samaan source-tiedostoon, käytä package-nimeä harj2. • Tee Demo2-luokalle konstruktori, jolla on yksi int-tyyppinen parametri. Konstruktori tallettaa arvon. • Pääohjelma (main) on Demo-luokassa • Luo Demo-luokan main-metodissa useita Demo2-objekteja ja talleta viittaukset DemoInt-tyyppisiin muuttujiin • Demo2 implementoi metodin show() joka tulostaa konstruktorissa annetun arvon • Kutsu show()-metodia jokaiselle luomallesi Demo2-objektille
Perintä • luokka voivat periytyä toisesta luokasta: • class A extends B … • tämä tarkoittaa että luokassa A on automaattisesti kaikki metodit ja muuttujat joita on luokassa B • luokka B on luokan A yläluokka (superclass) • luokka A voi myös ylikirjoittaa joitakin luokkaan B metodeja, ts. korvata ne omalla versiollaan • luokka A kelpaa luokan B tilalle esim. parametrien välityksessä: • void m(B param) {…}A a = new A();m(a); • ylikirjoitettuja metodeja kutsuttaessa käytetään automaattisesti ”oikeaa” versiota (polymorfismi)
Perintä • Luokka voi sekä periä yhden luokan että toteuttaa yhden tai useamman rajapinnan: • class A extends B implements X, Y { ... } • Kaikki luokat periytyvät luokasta java.lang.Object, siis esim. jos metodin parametri on Object-tyyppiä, voi sille välittää minkä tahansa olion • Myös String-oliot ja kaikki taulukot periytyvät Object-luokasta: void m(Object obj) {...} m(new Demo()); m(”abd”); m(new int[10]); m(1); // virhe, 1 ei ole objekti
Perintä • Perintä on samantapainen ominaisuus kuin rajapintojen käyttö, mutta perittävään luokkaan voi sisällyttää yhteistä toiminnallisuutta • Useimmiten kannattaa suosia rajapintoja ja käyttää perintää säästeliäästi • perintä tekee rakenteesta jäykemmän • luokalla voi olla vain yksi yläluokka
Cast (tyyppimuunnos) • muuttuja jolla johonkin luokkaan viitataan voi siis olla määritelty • interface-tyyppiseksi • yläluokan tyyppiseksi • Jos luokan todellinen tyyppi tiedetään ja halutaan käsitellä objektia sen tyyppisenä, pitää tehdä ”cast” (tyyppimuunnos) • B b = new A();b.metodiA(); // ei onnistu (oletetaan että metodiA on // määritelty yläluokassa A)A a = (A)b;a.metodiA(); // OK • castia tarvitaan erityisesti kokoelmaluokkia (java.util-pakkauksessa) käsiteltäessä: kokoelma palauttaa olion aina Object-tyyppisenä, se pitää muuntaa oikeaksi tyypiksi: • HashMap map = new HashMap(); • map.put(”1”,”aaa”);map.put(”2”,”bbb”);String s = (String)map.get(”2”);
Poikkeukset (exceptions) • try{ ... // normaali koodi // throw new Exception(”Sattui virhe”);}catch (Exception e){ // poikkeuskäsittely e.printStackTrace();}finally{ // close files etc. ...}
Poikkeukset (exceptions) • standardipakkaukset määrittelevät suuren joukon poikkeuksia eri tarkoituksiin • esim • java.io.IOException – yleinen tiedostovirhe • java.io.FileNotFoundException • java.io.EOFException • java.lang.IndexOutOfBoundsException • Poikkeukset on joko käsiteltävä tai välitettävä eteenpäin throws-attribuutilla: • void teeJotakin(String fname) throws IOException • { FileInputStream fis = new FileInputStream(fname); ... • }
Java-dokumentaatio • http://java.sun.com • http://java.sun.com/docs/ • http://java.sun.com/j2se/1.4.2/docs/index.html • Javadocs (API-luokkakirjasto) • http://java.sun.com/j2se/1.3/docs/api/ • http://java.sun.com/j2se/1.4.2/docs/api/
Harjoitus 3 - perintä • Tee seuraavat luokat • class Demo • main • class DemoBase • void show() • class Demo1 extends DemoBase • Demo1(int i) • void show() • class Demo2 extends DemoBase • Demo2(int i) • Kaikki luokat voi tehdä samaan source-tiedostoon, käytä package-nimeä harj3. • tee Demo1/2-luokille konstruktori, jolla on yksi int-tyyppinen parametri. Konstruktori tallettaa arvon. • Pääohjelma (main) on Demo-luokassa • Luo Demo-luokan main-metodissa Demo1- ja Demo2-tyyppiset objektit ja talleta viittaukset DemoBase-tyyppisiin muuttujiin • DemoBase sisältää metodin show() joka tulostaa konstruktorissa annetun arvon esim. muodossa ”DemoBase: ” + i • Lisää Demo1-luokkaan oma versio show()-metodista (”Demo1: ” + i) • Kutsu show()-metodia jokaiselle Demo1/2-objektille
Luokkakirjasto • Javan mukana tulee standardiluokkakirjasto (paketit java.*, javax.* ja muita) • muihin tarkoituksiin luokkakirjastoja toimitetaan yleensä jar-paketteina • java.lang.* • kielen perusluokat, ei tarvitse import-määritystä • java.lang.Object - ”kaikkien luokkien äiti” • java.lang.System, java.lang.Runtime - ajoaikainen ympäristö • java.lang.String - merkkijonoluokka • java.lang.Integer, Long,… - perustietotyypit
Luokkakirjasto • Javan mukana on aina standardiluokkakirjasto. Se vastaa muiden kielten ajoaikaista ympäristöä, nyt vaan kaikki funktiot ovat luokkien sisällä ja luokat taas pakkauksissa. • Perusluokat ovat pakkauksessa java.lang, esim. • java.lang.String • java.lang.System • java.lang.Thread • Tiedostojen käsittelyyn liittyvät luokat ovat pakkauksessa java.io, esim • java.io.File • java.io.InputStream • java.io.OutputStream
Luokkakirjasto • Hyödyllisiä apuluokkia on pakkauksessa java.util, esim: • java.util.Vector, java.util.ArrayList ym. • java.util.StringTokenizer • TCP/IP-socketkutsut ovat pakkauksessa java.net, esim: • java.net.Socket • java.net.ServerSocket • java.net.URL • java.net.HttpURLConnection • SQL/JDBC-kutsut ovat pakkauksessa java.sql, esim: • java.sql.Connection • java.sql.PreparedStatement • java.sql.ResultSet
Luokkakirjasto • java.io.* - tiedostojen käsittely • InputStream, OutputStream • stream-tyyppisen käsittelyn (”tavuvirta”, peräkkäisluku tai kirjoitus) perusluokat • näistä peritttyjä luokkia eri tyyppiseen I/O:hon • FileInputStream, FileOutputStream • DataInputStream, DataOutputStream • tietomuotokonversiot • PrintStream • merkkijonojen tulostus • ByteArrayInputStream • lukee datan suoraan puskurista