v46 Java allmänt Objektorientering, polymorfism Instans- och klassvariabler (static) Skräpsamling v47 Undantag ("exceptions") Arv, klasser och gränssnitt ("interfaces"), paket Applet, inledande (inför inlämningsuppgift 1) Trådar v48 JDBC, inlämningsuppgift 2 Java och nätverk v49 Java och nätverk, forts. Genomgång av inlämningsuppgift 2 Repetition v50 Grafisk applikation och Javadoc Mera Applet Grafiska gränssnitt, händelsestyrning v51 Grafikhantering (omritning) Strömmar I/O Filhantering Säkerhet i Java JavaBeans v52-2 Självstudier v3 TentaInlämningsuppgifterna ska redovisas före tentamen.
Körexempel:#include <stdio.h> int main(int argc, char* argv[]) { printf("Hello, world!\n"); return 0; } /* main */
Filen hello.cpp:linux> gcc -Wall hello.c -o hello linux> ./hello Hello, world! linux>
Körexempel:#include <iostream> int main(int argc, char* argv[]) { std::cout << "Hello, world!\n"; } // main
Filen Hello.java:linux> g++ -Wall hello.cpp -o hello linux> ./hello Hello, world! linux>
Körexempel:public class Hello { public static void main(String[] args) { System.out.println("Hello, world!"); } } // Hello
Java-programmet är inte en vanlig körbar fil ("exe-fil"), utan måste köras av en Java-tolk, den virtuella maskinen (JVM).linux> javac Hello.java linux> java Hello Hello, world! linux>
En åsikt är att Microsofts C#, och hela .NET-arkitekturen, är en kopia av Sun:s Java, "as close as legally possible", dvs en så exakt kopia som det går att göra utan att bli stämd.class HelloWorld { public static void Main() { System.Console.WriteLine("Hello, world!"); } }
Körexempel 1:#include <stdio.h> int main(int argc, char* argv[]) { printf("What's your name: "); char* s; gets(s); printf("Hello, %s!\n", s); return 0; } /* main */
Körexempel 2:linux> ./helloname What's your name: Bob Hello, Bob! linux>
linux> ./helloname What's your name: Bob med det långa namnet Hello, Bob med det långa namnet! Segmentation fault (core dumped) linux>
Det finns alltså flera sätt att köra Java. Här är ett av dem, som fungerade 2003, men nu är det fel versioner:
Omgivningsvariabler ("environment"):
Eller en klickbar fil för den late och smarte. Kalla den exempelvis startjava.bat:set path=%path%C:\Program\Java\j2sdk1.4.2_02\bin set classpath=M:\Javakursen
(Kalla inte filen java.bat. Då kommer Windows att starta den i stället för java-tolken när du skriver java.)@ECHO OFF set path=%path%;C:\Program\Java\j2sdk1.4.2_02\bin set classpath=M:\Javakursen M: cd M:\Javakursen %SystemRoot%\SYSTEM32\CMD.EXE
Körexempel:// Det finns minst ett fel i det här programmet. import java.io.*; class Rektangelkalkylator { public static void main(String args[]) { int a = 0, b = 0; String buf; BufferedReader kbd_reader = new BufferedReader(new InputStreamReader(System.in)); try { System.out.print("Ge sida a: "); buf = kbd_reader.readLine(); a = Integer.parseInt(buf); System.out.print("Ge sida b: "); buf = kbd_reader.readLine(); b = Integer.parseInt(buf); System.out.println("Area: " + a * b); System.out.println("Omkrets: " + 2*a + 2*b); } catch (IOException e) { System.out.println("Kunde inte läsa!"); } } // main } // Rektangelkalkylator
Fixa felet. Sen:linux> javac Rektangelkalkylator.java linux> java Rektangelkalkylator Ge sida a: 5 Ge sida b: 4 Area: 20 Omkrets: 108 linux>
Jämför med vad som händer i C++. Programmet rektangelkalkylator.cpp:linux> java Rektangelkalkylator Ge sida a: Bengt Exception in thread "main" java.lang.NumberFormatException: For input string: "Bengt" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:447) at java.lang.Integer.parseInt(Integer.java:497) at Rektangelkalkylator.main(Rektangelkalkylator.java:15) linux>
Körexempel (C++):#include <iostream> using namespace std; int main(int argc, char* argv[]) { int a = 0, b = 0; cout << "Ge sida a: "; cin >> a; cout << "Ge sida b: "; cin >> b; cout << "Area: " << a * b << "\n"; cout << "Omkrets: " << 2*a + 2*b << "\n"; } // main
Fångar Java alla fel? Nej:linux> make rektangelkalkylator g++ rektangelkalkylator.cpp -o rektangelkalkylator linux> ./rektangelkalkylator Ge sida a: Bengt Ge sida b: Area: 0 Omkrets: 0 linux>
linux> java Rektangelkalkylator Ge sida a: 1000000 Ge sida b: 1000000 Area: -727379968 Omkrets: 4000000 linux>
Tips: IOStreamDemo.java ur Bruce Eckels Thinking in Java, 3d Ed, visar upp typiska användningar av Java-I/O. Det finns förklaringar i online-boken.
Filen Main.java:public class Rektangel { public Rektangel(int a, int b) { this.a = a; this.b = b; } public int omkrets() { return 2 * this.a + 2 * this.b; } public int area() { return a * b; } private int a = 0, b = 0; } // Rektangel
Körexempel:import java.io.*; public class Main { public static void main(String args[]) { BufferedReader kbd_reader = new BufferedReader(new InputStreamReader(System.in)); int a, b; String buf; try { System.out.print("Ge sida a: "); buf = kbd_reader.readLine(); a = Integer.parseInt(buf); System.out.print("Ge sida b: "); buf = kbd_reader.readLine(); b = Integer.parseInt(buf); Rektangel rektangel = new Rektangel(a, b); System.out.println("Area: " + rektangel.area()); System.out.println("Omkrets: " + rektangel.omkrets()); } catch (IOException e) { System.out.println("Kunde inte läsa!"); } } // main } // Main
linux> javac Rektangel.java linux> javac Main.java linux> java Rektangel Exception in thread "main" java.lang.NoSuchMethodError: main linux> java Main Ge sida a: 5 Ge sida b: 4 Area: 20 Omkrets: 18 linux>
Filen Rektangel.java:
Körexempel:import java.io.*; class Rektangel { public Rektangel(int a, int b) { this.a = a; this.b = b; } public int omkrets() { return 2 * this.a + 2 * this.b; } public int area() { return a * b; } private int a = 0, b = 0; public static void main(String args[]) { BufferedReader kbd_reader = new BufferedReader(new InputStreamReader(System.in)); int a, b; String buf; try { System.out.print("Ge sida a: "); buf = kbd_reader.readLine(); a = Integer.parseInt(buf); System.out.print("Ge sida b: "); buf = kbd_reader.readLine(); b = Integer.parseInt(buf); Rektangel rektangel = new Rektangel(a, b); System.out.println("Area: " + rektangel.area()); System.out.println("Omkrets: " + rektangel.omkrets()); } catch (IOException e) { System.out.println("Kunde inte läsa!"); } } // main } // Rektangel
Man kan ha en main-funktion i varje klass. Bra för testning!linux> javac Rektangel.java linux> java Rektangel Ge sida a: 45 Ge sida b: 34 Area: 1530 Omkrets: 158 linux>
Ett misslyckat körexempel, för det finns ingen main-metod:import java.applet.*; import java.awt.*; public class Hello extends Applet { public void paint(Graphics gr) { gr.drawString("Hello, world!", 100, 100); } // paint } // Hello
Filen hello.html:linux> javac Hello.java linux> java Hello Exception in thread "main" java.lang.NoSuchMethodError: main linux>
Appleten i en webbläsare:<html> <head> <title>Ett appletexempel</title> </head> <body> <applet code="Hello.class" width="200" height="200"></applet> </body> </html>
Har du en Java-plugin i din webbläsare? I så fall bör du se appleten här, "på riktigt":
// Sträcker sig över resten av raden /* Kan sträcka sig över flera rader */
boolean 1 bit false eller true char 16 bitar Unicode-tecken byte 8 bitar -128 .. 127 short 16 bitar -32768 .. 32767 int 32 bitar -2147483648 .. 2147483647 long 64 bitar -9223372036854775808 .. 9223372036854775807 float 32 bitar 3.40282347E+38 .. 1.40239846E-45 double 64 bitar 1.79769313486231570E+308 .. 4.94065645841246544E-324
Det finns flera olika sorters arrayer! Ingen av dem fungerar som i C och C++.
De inbyggda arrayerna kan lagra både primitiva typer och objekt. Man måste (oftast) göra new.
Exempel:
int[] intarray = new int[10]; int intarray[] = new int[10]; String[] fruits = { "Äpplen", "Päron", "Apelsiner" }; int intarray[10]; // Ger kompileringsfel!
Notera att bitskiftningsoperatorerna << och >>, som i C++ överlagrats för in- och utmatning, bara är bitskiftningsoperatorer i Java.
Ett djur har ett namn (variabeln name) och en vikt (variabeln weight), och det kan äta (metoden eat):
(Jag använder engelska namn, men det hade funkat bra med svenska, inklusive ÅÄÖ!)class Animal { protected String name; private int weight; public Animal(String n, int w) { name = n; weight = w; } public void eat(String food) { System.out.println(name + " eats some " + food + "."); weight += 0.5; } } // class Animal
En fisk är ett djur. Den har alla egenskaper som ett djur har (nämligen namn och vikt) och den kan allt som ett djur kan (nämligen äta). Men dessutom har den en största djup som den kan simma på, och den kan simma:
En fågel är också ett djur. Den har alla egenskaper som ett djur har (nämligen namn och vikt) och den kan allt som ett djur kan (nämligen äta). Men dessutom har den en högsta flyghöjd, och den kan flyga. Dessutom beter den sig lite speciellt när den äter: först fladdrar den med vingarna av lycka över att ha fått matm och därefter äter den precis som ett vanligt djur.class Fish extends Animal { private int maxDepth; public Fish(String n, int w, int d) { super(n, w); maxDepth = d; } public void swim() { System.out.println(name + " swims."); } } // class Fish
Vi provkör klasserna med hjälp av klassen Zoo och dess main-metod:class Bird extends Animal { private int maxAltitude; public Bird(String n, int w, int a) { super(n, w); maxAltitude = a; } public void fly() { System.out.println(name + " flies."); } public void eat(String food) { System.out.println(name + " flutters its wings."); super.eat(food); } } // class Bird
Utmatning:class Zoo { public static void main(String[] args) { Bird tweety = new Bird("Tweety", 3, 1000); tweety.eat("corn"); tweety.fly(); Fish b = new Fish("Bubbles", 13, 100); b.eat("fish food"); b.swim(); Animal w = new Fish("Willy", 4000, 1000); w.eat("tourists"); // w.swim(); -- Doesn't work. See below. } } // class Zoo
Kommentarer:Tweety flutters its wings. Tweety eats some corn. Tweety flies. Bubbles eats some fish food. Bubbles swims. Willy eats some tourists.
Lägg märke till att klassen Bird har en egen metod som heter eat. Det finns en i Animal också, men den nya ersätter eller "döljer" (engelska: overrides) den gamla, och kommer att användas i alla Bird-objekt. Om man har en metod i en subklass med samma namn (och argument) som en metod i superklassen, så döljer metoden i subklassen metoden i superklassen. Om man trots det vill anropa metoden i superklassen kan man använda super, som är objektet men "tolkat som om det enbart hörde till superklassen". Det är vad vi gör i metoden eat: efter att ha fladdrat med vingarna så ska fågeln faktiskt äta, och det görs med ett anrop till super.eat.
Angående w.swim(): Variabelb w är av typen Animal, och Animal har ingen metod som heter swim. Variabeln w innehåller Willy, som är en Fish, och Fish har ju en swim-metod, så den skulle ha kunnat anropas när programmet körs. Men kompilatorn måste vara säker på att det aldrig kan uppstå ett typfel! Därför kontrollerar den vid kompileringstillfället att anropet aldrig kan misslyckas. Det betyder att varje objekt som kan lagras i variabeln w måste vara av en klass som har en swim-metod.
En Figur har en mittpunkt, som anges med koordinaterna x_center och y_center. Man kan räkna ut dess area och omkrets, och den högsta x-koordinat och y-koordinat som täcks av figuren.
Men! Hur figuren ser ut, och hur man räknar ut area och omkrets, beror ju helt på vilken figur det är! Därför kan de metoderna inte implementeras i klassen Figur, utan "lämnas" till subklasserna. Det kallas att metoderna är abstrakta. Eftersom det finns abstrakta metoder i klassen, kan man inte skapa objekt av den typen, så hela klassen blir abstrakt.
En Rektangel är en sorts Figur, och den innehåller förstås ett sätt att räkna ut omkretsen och ett sätt att räkna ut arean. Klassen Rektangel är inte abstrakt, utan man kan skapa Rektangel-objekt. En Rektangel har inte bara en mittpunkt, utan dessutom två sidor. Vi skriver en konstruktor med de extra parametrarna.public abstract class Figur { public Figur(int x, int y) { this.x_center = x; this.y_center = y; } // Figur public abstract int max_x(); public abstract int max_y(); public abstract int area(); public abstract int omkrets(); protected int x_center, y_center; } // class Figur
En Cirkel är en annan sorts Figur:public class Rektangel extends Figur { public Rektangel(int x, int y, int sida, int hojd) { super(x, y); this.sida = sida; this.hojd = hojd; } // Rektangel public int max_x() { return super.x_center + this.sida / 2; } // max_x public int max_y() { return super.x_center + this.hojd / 2; } // max_y public int area() { return this.sida * this.hojd; } // area public int omkrets() { return 2*this.sida + 2*this.hojd; } // omkrets private int sida, hojd; } // class Rektangel
Klassen FigurMain innehåller metoden main:public class Cirkel extends Figur { public Cirkel(int x, int y, int radie) { super( x, y ); this.radie = radie; } // Cirkel public int max_x() { return super.x_center + this.radie; } // max_x public int max_y() { return super.y_center + this.radie; } // max_y public int area() { return (int)(Math.PI * this.radie * this.radie); } // area public int omkrets() { return (int)(2*Math.PI * this.radie); } // omkrets public int diameter() { return this.radie + this.radie; } // diameter private int radie; } // class Cirkel
Körexempel:public class FigurMain { public static void main(String args[]) { Figur[] figurer = new Figur[4]; figurer[0] = new Rektangel( 10, // x 10, // y 10, // sida 10 ); // hojd figurer[1] = new Cirkel( 10, // x 10, // y 10 ); // radie figurer[2] = new Rektangel( 20, // x 20, // y 20, // sida 20 ); // hojd figurer[3] = new Cirkel( 20, // x 20, // y 20 ); // radie for (int index = 0; index < figurer.length; index++) { if (figurer[index] instanceof Cirkel) { System.out.println("Cirkel:"); System.out.println(" Diameter: " + ((Cirkel)figurer[index]).diameter() ); } else { System.out.println("Rektangel:"); } // if System.out.println(" Högsta x: " + figurer[index].max_x()); System.out.println(" Högsta y: " + figurer[index].max_y()); System.out.println(" Area: " + figurer[index].area() ); System.out.println(" Omkrets: " + figurer[index].omkrets()); } // for } // main } // class FigurMain
Rektangel: Högsta x: 15 Högsta y: 15 Area: 100 Omkrets: 40 Cirkel: Diameter: 20 Högsta x: 20 Högsta y: 20 Area: 314 Omkrets: 62 Rektangel: Högsta x: 30 Högsta y: 30 Area: 400 Omkrets: 80 Cirkel: Diameter: 40 Högsta x: 40 Högsta y: 40 Area: 1256 Omkrets: 125
Nu har vi en instans av Cirkel. Variabeln cirkel refererar till den cirkeln. (Ungerfär som pekare i C.)Cirkel cirkel; // får värdet null cirkel = new Cirkel( 10, 10, 10 );
Nu refererar både cirkel och cirkel2 till samma objekt!Cirkel cirkel2; // får värdet null cirkel2 = cirkel;
C++:s delete finns inte i Java, och behövs inte. Java har automatisk skräpsamling (engelska: garbage collection).
<modifier> class <name> [ extends <baseclassname> ] [ implements <interfacename> ] { . . . <variable definitions> . . . <function definitions> . . . }
Anrop av area-metoden i Cirkel. Inuti metoden refererar variabeln this till objektet, dvs cirkeln cirkel.Cirkel cirkel = new Cirkel( 10, 10, 10 ); System.out.println("Area: " + cirkel.area());
Nu kan man peta på den utifrån:public int radie;
Cirkel cirkel = new Cirkel( 10, 10, 10 ); cirkel.radie = 27; // som en struct i C
public void rita(int skala) { /* ... */ } public void rita(int x, int y) { /* ... */ }
public Figur(int x, int y) { /* ... */ } public Figur() { /* ... */ }
Men Java har automatisk skräpsamling! Inte som i C++, där destruktorn måste städa upp allt som ett objekt allokerat.
Lita inte på finalize, till exempel för att stänga filer och ta bort fönster. Man har ingen aning om när den körs.