' $ ' $ Java för den som kan C++ Vad är Java? Lätt och svårt 1. (Ganska) nytt programmeringsspråk (1995) • Själva språket ganska litet 2. Syntaktiskt likt C och C++ • Automatisk minneshantering (ingen pekarhantering) 3. Plattformsoberoende • Stor mängd paket — omöjligt att kunna allt 4. Grafik och grafiska användargränssnitt 5. Objektorienterat • Ofta högre ambition: grafiska gränssnitt, ljud, rörliga bilder, Internet, trådat . . . 6. Möjligheter till parallellitet 7. Ljud och bild 8. Internet & % & 2 1 ' % $ ' $ Hur kör man ett program? Exempel: En klassiker 1. Skapa programmet på en fil med hjälp av en texteditor t ex emacs och lagra på en fil med namnet HelloWorld.java // Ett första Java-program som skriver // ut ett meddelande på terminalen 2. Kompilera med följande kommando : class HelloWorld { $ javac HelloWorld.java Kompilerade programmet lagras på filen HelloWorld.class public static void main(String [] args) { System.out.println("Hello world!"); } 3. Kör programmet genom att ge kommandot } $ java HelloWorld & % 3 & % 4 ' $ ' $ Körning av första exemplet kursa$ ls HelloWorld.java Exempel 3: En ”funktion” kursa$ cat HelloWorld.java class Factorial { public static long fact(int n) { long result = 1; for ( int i= 1; i<=n; i++ ) result *= i; return result; } // Ett första Java-program som skriver // ut ett meddelande på terminalen class HelloWorld { public static void main(String [] args) { System.out.println("Hello world!"); } public static void main(String [] args) { for ( int i = 0; i <=10; i++ ) { System.out.println( i + "! = " + fact(i) ); } } } kursa$ javac HelloWorld.java kursa$ ls HelloWorld.class HelloWorld.java kursa$ java HelloWorld Hello world! kursa$ & } % & 5 ' % 6 $ ' $ Programstruktur och terminologi • Ett program består av en eller flera klasser Exempel • Java saknar globala funktioner och variabler - allting är förpackat i klasser // Punkt i planet • Varje klass lagras på en fil med samma namn public class Point { double x, y; • En klass beskriver någon typisk enhet i programmet // Konstruktor • En klass innehåller data (attribut) och metoder public Point( double xp, double yp ) { x = xp; y = yp; } • När ett program exekverar skapas ett antal instanser av klasserna — så kallade objekt } • Objekten kommunicerar med varandra genom att anropa varandras metoder & % 7 & % 8 ' $ public class Circle { Point center; double radius; ' $ public Circle( Point cen, double rad ) { center = cen; radius = rad; } • Objekt skapas med new public void scale(double sf) { radius = sf*radius; } • Referensvariabler håller reda på objekt • En referensvariabel kan vara null public double area() { return Math.PI*radius*radius; } • ”Punktnotation” används för att referera attribut och metoder • Exekveringen börjar i main public static void main(String [] args) { Point p = new Point( 0.5, -3.5 ); Circle c = new Circle( p, 1.0 ); Circle d = c; System.out.println("Area of c: " + c.area()); c.scale(2.0); System.out.println("Area of d: " + d.area()); } } & % & 9 ' % 10 $ ' $ Exempel: Tärning public class Dice { private int noSides; private int value; public Dice() • Två konstruktorer - s.k. överlagring • Skyddsnivåer: public, private { noSides = 6; } • Fler finns: ”paket” (eng. package) och protected public Dice(int nS) { noSides = nS; } public int roll() { return value = (int) (Math.random()*noSides) + 1; } • Privata attribut, publika metoder • Tilldelning har värde • Skulle kunna ändra antal sidor om t ex public int get() { return value; } – public void setNoSides(int n) och, ev. public static void main(String [] args) { Dice t = new Dice(); for ( int i = 1; i<20; i++ ) System.out.println(t.roll()); } – public int getNoSides() } & % 11 & % 12 ' $ ' $ import extra.*; public class CheckDice { public static void main(String[] args) { int nSides; Std.out.print("Number of sides: "); nSides = Std.in.readInt(); int[] freq = new int[nSides]; Dice d = new Dice(nSides); • import av Skansholms IO-paket • Flera huvudprogram (main()) - bara ett används • Arrayer skapas dynamiskt med new for (int i= 1; i<=1000; i++ ) { freq[d.roll()-1]++; } • Arrayer hanteras med referenser • Minsta index 0 i array for (int i= 0; i<nSides; i++) Std.out.println( (i+1) + "\t" + freq[i] ); } } & % & 13 ' kursa$ Number 1 2 kursa$ Number 1 2 kursa$ Number 1 2 kursa$ Number 1 2 3 4 5 6 7 % 14 $ java CheckDice of sides: 2 487 513 java CheckDice of sides: 2 507 493 java CheckDice of sides: 2 492 508 java CheckDice of sides: 7 162 140 127 127 162 133 149 ' $ Klasshierarkier Nya klasser kan definieras som specialiseringar av existerande (egna eller andras...) class Point3D extends Point { double z; public Point3D( double x, double y, double z ) { super(x,y); this.z = z; } public double distance() { return Math.sqrt(x*x + y*y +z*z); } } & % 15 & % 16 ' $ ' $ Enkla datatyper • Basklass — subklass • extends Typ värden storlek exempel • super() byte heltal 1 byte -127, 47 • Subklassen ”ärver” basklassens attribut och metoder short heltal 2 byte 4711 int heltal 4 byte -748471 • Man bygger ofta ut fördefinierade klasser (ex GraphicsApplet och GraphicsTest ovan) long heltal 8 byte 434112345L float flyttal 4 byte -4.57e10f double flyttal 8 byte 3.123e-128 • private – vägra åtkomst från subklasser boolean logisk 1 byte (?) true, false • final – förhindrar ”subklassning” char tecken 2 byte ’x’, ’4’, ’+’ & % & % 18 17 ' $ ' $ Identifierare Vanliga regler för namn på klasser, metoder, variabler etc. men, dessutom, även nationella bokstäver — t.ex. å, ä, ö. Namnkonventioner Får inte vara samma som reserverade ord (t.ex. class, if, for . . . ) • Namn på klasser börjar med versal • Konstanter skrivs med versaler (t. ex. PI för π) Skillnad på VERSALER och gemena. Exempel på legala • Metoder och variabler skrivs gemena och illegala namn: Kö lastElement tömListan EULER html2ps l110lO0l0_0O • Versaler används för att öka läsligheten (t. ex. linesPerPage) 12x x+2 public • Använd namn som ökar läsbarheten i programmet! (sista är exempel på ett dåligt namn) & % 19 & % 20 ' $ ' $ Variabler Variabler måste typdeklareras och kan ges initialvärden i deklarationen. Operatorer Operatorer för aritmetik, tilldelning och inkrement som i C och C++: Exempel: int antal, storlek = 4; float friktion = 1.0, vinkel = Math.PI/180.0; x = 2*y + 16; i1 = i1 + x; x = y = 16; x += 3; result *= 1 + 2; i++; Typdeklarationer kan föregås av en eller flera modifierare som anger speciella egenskaper: private int storlek = 4; public final double EULER =0.5772; static char EOL = ’\n’; & % & 22 21 ' % $ ' $ In- och utmatning • Mycket generellt i Java Typkonverteringar – Många olika källor • Java konverterar automatiskt när det kan ske ”riskfritt” – Grafiska användargränssnitt – Nationella variationer • Explicit med s.k. typecasts. Ex: (short) • Komplicerat • Vid aritmetik omvandlas byte, short till int – Många detaljer – Fel kan uppstå • Om en operand är long så omvandlas den andra till long (om den är av heltalstyp) • Saknar medel för enkel IO mot terminal – System.out.print() • Funktioner i Math returnerar double • Hjälpklasser: ExtendedReader, ExtendedWriter och Std & % 23 & % 24 ' $ Utmatning med Skansholms hjälpklass Några av metoderna i ExtendedReader println() readLine() print(x) readLong() minst n positioner readDouble() println(x,n) d decimaler println(x,n,d) printExp(x,n,d) exponentform returnerar int lookAhead() nästa tecken skip(n) hoppa över n more() tömmer bufferten & readChar() skipLine() printlnExp(x,n,d) flush() läser rad readWord() println(x) print(x,n,d) $ Inmatning med Skansholms hjälpklass Några av metoderna i ExtendedWriter print(x,n) ' % true om fler icke-blanka & 25 ' Exempel: Tabell med funktionsvärden 26 $ class TableIO { public static void main(String [] args) { double x, xlow, xhigh; int number; Std.out.print("Undre gräns: "); xlow = Std.in.readDouble(); Std.out.print("Övre gräns: "); xhigh = Std.in.readDouble(); Std.out.print("Antal värden: "); number = Std.in.readInt(); double step = (xhigh - xlow) / (number-1); for ( int i = 1; i<=number; i++ ) { x = xlow + (i-1)*step; Std.out.print(x,10,2); Std.out.print(Math.log(x),12,3); Std.out.print(Math.exp(x),12,3); Std.out.println(); } } } % 27 ' $ kursa$ java TableIO Undre gräns: 0.1 Övre gräns: 2.0 Antal värden: 20 0.10 -2.303 0.20 -1.609 0.30 -1.204 0.40 -0.916 0.50 -0.693 0.60 -0.511 0.70 -0.357 0.80 -0.223 0.90 -0.105 1.00 0.000 1.10 0.095 1.20 0.182 1.30 0.262 1.40 0.336 1.50 0.405 1.60 0.470 1.70 0.531 1.80 0.588 1.90 0.642 2.00 0.693 kursa$ import extra.*; & % 1.105 1.221 1.350 1.492 1.649 1.822 2.014 2.226 2.460 2.718 3.004 3.320 3.669 4.055 4.482 4.953 5.474 6.050 6.686 7.389 & % 28 ' $ ' $ Klassen String • Ett objekt ur klassen String består av en följd av char Kontrollstrukturer • Strängkonstanter omges med citationstecken String s = "Omge strängar med \"!" if, for, while, do-while och case som i C och C++. Relationsoperatorer som i C och C++. • Objekt av typen String är oföränderliga. Alla operationer nedan som resulterar i strängar skapar nya sådana. Logiska uttryck skall vara av typen boolean. De logiska operatorerna skrivs !, && och || • Operatorn + konkatenerar strängar • Tecknen i strängen numreras från 0 & % & 29 ' % 30 $ ' $ import extra.*; public class Palindrom { Några metoder: public static void main(String[] args) { String w; int n; boolean pal; while (Std.in.more()) { w = Std.in.readWord(); w = w.toUpperCase(); if ( w.equals("STOP") || w.equals("QUIT")) break; n = w.length(); pal = true; for ( int i=0; i < n/2; i++) { if (w.charAt(i)!=w.charAt(n-1-i)) { pal = false; break; } } if ( pal ) System.out.println(w + " palindrom"); else System.out.println(w + " ej palindrom"); } System.out.println("Bye!"); } length() charAt(n) substring(n) substring(n,m) compareTo(s) equals(s) indexOf(c) indexOf(s) replace(c1,c2) toUpperCase() toLowerCase() & % 31 & } 32 % ' $ ' $ Exempel Antag att jag vill använda katalogen java i min hemkatalog för att lagra paketet tomsSpecial (och kanske andra paket). Paket Klasser kan samlas ihop i så kallade paket • Placera raden export CLASSPATH=.:/home/tom/java i filen ~/.bashrc • Ett paket skall ha ett namn • Ingående klasser skall lagras i en katalog med samma namn • Skapa katalogen /home/tom/java/tomsSpecial/ • Varje fil skall inledas med en package-sats med paketnamnet • Lägg alla filer/klasser som hör till paketet i denna katalog • import-satsen används för att ange paket som skall användas • Lägg satsen package tomsSpecial i först i varje java-fil • Miljövariabeln CLASSPATH anger var paket skall sökas • Inkludera satsen import tomsSpecial.* när klasser ur paketet skall användas & % & 34 33 ' $ • Man kan göra underpaket som lagras i underkataloger $ Mer om klasser • Ingen speciell ordning krävs men . . . • Observera att ”.” inkluderades i CLASSPATH • Instansvariablerna synlighet är sällan publika utan • Om ingen package-sats placeras klassen i ett anonymt paket – privata eller – skyddade (protected) eller, möjligen, • För att en klass skall kunna användas från andra paket måste den vara public – paketsynliga. • Om ingen skyddsnivå (synlighet) anges är klassen/metoden/attributet endast åtkomlig för andra klasser i samma paket • Instansvariabler har defaultvärden beroende på typ (typiskt 0) • Instansvariabler kan initieras i deklarationen till godtyckliga uttryck (ingående variabler måste vara definierade) • En fil kan innehålla flera klasser men endast en får vara public % 35 ' class namn { deklarationer av instansvariabler definition av metoder } • Endast klasserna i tomsSpecial importeras — inga klasser i eventuella underkataloger & % • Instansvariabler kan anges som final vilket förhindrar ändring (dvs en konstant & 36 % ' $ ' $ Metodefinition modifierare typ namn(typ1 p1 , typ2 p2 , . . . ) { lokala variabler och satser } Metodanrop • Från metod i samma klass: metodnamn(argumentlista) • Modifierarna anger t.ex. synlighet • Från metod i annan klass: referens.metodnamn(argumentlista) • Lokala variabler har inga defaultvärden! • Om typen inte är void så måste en sats • Om static-metod i annan klass: klassnamn.metodnamn(argumentlista) (Ex: Math.exp(x)) return u; där u är ett uttryck av rätt typ. • Metoder kan ha samma namn om de har olika signatur dvs skiljer sig i parameterantal och/eller typ (överlagring) & % & 38 37 ' Konstruktorer och destruktorer $ • Attributen kan tilldelas värden direkt i deklarationen (alternativt erhålla defaultvärden) $ Vid anrop sker 1. De uttryck som givits som argument beräknas 2. De beräknade värdena förs över till parametrarna • En konstruktor är en metod som har samma namn som klassen och som saknar typ (man kan ju också säga att den har typ men saknar namn . . . ) 3. Internt i metoden används parametrarna lokala variabler — de kan t.ex. tilldelas nya värden • Om man inte definierar någon konstruktor tillhandahåller systemet en defaultkonstruktor som saknar parametrar och inte gör någonting 39 ' Parameter och resultatöverföring • Man kan definiera en eller flera konstruktorer för mer komplicerade initieringar • Om man definierar en eller flera konstruktorer så tillhandahåller inte systemet någon defaultkonstruktor — om man vill ha en parameterlös konstruktor så får man skriva en själv & % 4. Inga värden återföres via parametrarna vi return Metoden kallas värdeanrop (eng. call by value) och möjliggör således ej returparametrar. (Kan dock åstadkommas genom att skicka referenser till objekt.) % & % 40 ' $ Referenser • Observera att relationsoperatorerna jämför adresserna dvs som de står för fysiskt samma objekt — inte huruvida objekten ser lika ut • Deklarationen Dice t; gör inte t till en Dice utan till en referens till en Dice • Om ingen referens till ett objekt är det ”borttappat” • Referenser kan tilldelas till referensvariabler (av rätt typ) och jämföras med == och != • Borttappade element samlas ihop och återanvänds (skräpsamling, garbage collection) • Instansvariabler av referenstyp initieras till null • Skräpsamlingen pågår i hela tiden i en separat tråd med låg prioritet • this är en referens till det ”egna” objektet % & 41 ' $ • Flera referenser kan peka till samma objekt. Blir resultatet av tilldelningen t1 = t2; • Objekt skapas med new som returnerar en referens (dvs en pekare eller adress) till det skapade objektet. & ' % 42 $ ' $ Några kommentarer ut C++-perspektiv • Referenser kan skickas som parametrar till en metod (objekt kan naturligtvis inte skickas) • Inga referensanrop • Värdeanrop som vanligt • Ingen delete-operation • Man skulle kunna säga att objekt överförs med referensanrop men det är faktiskt referenser till objekt som överförs med värdeanrop • Ej samma behov av en destruktor eftersom Java själv samlar skräp • Ej något implicit behov av en kopieringskonstruktor • Man kan definiera en destruktor (finalize()) som då anropas av skräpsamlaren • Om objektet förändras av metoden så har det effekt • Man vet dock inte när eller ens om den anropas eftersom skräpsamlaren exekverar för sig och eventuellt bara om det behövs • Man kan säga att objekten existerar globalt och är åtkomliga överallt där man har en referens till dem • (Man kan anropa skräpsamlaren explicit: System.gc() men det verkar ändå inte garantera att alla ”borttappade” objekt blir ihopsamlade) • En metod kan returnera referenser som funktionsvärden & % 43 & % 44 ' $ Skapa kopior av objekt public class Circle { Point center; double radius; ' Många standardklasser har en clone()-metod för att skapa kopior. Om man vill använda namnet clone så måste man göra så här: $ public class Circle { Point center; double radius; public Circle( Point cen, double rad ) { center = cen; radius = rad; } public Circle( Point cen, double rad ) { center = cen; radius = rad; } public Circle( Circle c) { // konstruktor center = c.center; radius = c.radius; } public Circle( Circle c) { center = c.center; radius = c.radius; } public Circle copy() { // metod return new Circle( center, radius ); } public Object clone() { return new Circle(this); // t ex ... } public static void main(String [] args) { Circle c = new Circle( new Point(0.,0.), 1.0 ); Circle d = c; Circle e = new Circle(c); Circle f = c.copy(); } public static void main(String [] args) { Circle c = new Circle( new Point(0.,0.), 1.0 ); Circle h = (Circle) c.clone(); } } } & % Egentligen bör man implementera ett interface . . . & 45 ' % 46 $ ' $ Några exempel på jämförelsefunktioner public class Circle { Point center; double radius; Jämförelser av objekt • Relationsoperatorerna == och != jämför bara referenserna. public boolean equals(Circle c) { return Math.abs(radius-c.radius) < 1.e-10; } • Alla objekt har en metod equals() som jämför objekt innehållsmässigt byte för byte public int compareTo(Circle c) { return (int) (radius - c.radius); } • I regel definierar man dock en egen equals() public int compare(Circle c) { if ( radius == c.radius ) return 0; else return radius < c.radius ? -1 : 1; } • Referenser kan inte jämföras storleksmässigt men man kan naturligtvis definiera egna metoder för att jämföra objekt public boolean lessThan(Circle c) { return radius < c.radius; } & % 47 & % 48 ' $ Klassvariabler ' Exempel public class Circle1 { Point center; double radius; int id; static int nCircles = 0; • Hittills har alla dataattribut varit instans-variabler dvs varje objekt har sin egen upplaga av dessa • Man kan också ha klass-variabler som är gemensamma för alla objekt i klassen vilket anges med static public Circle1( Point cen, double rad ) { center = cen; radius = rad; id = ++nCircles; } • En klassvariabel kan referas på samma sätt vanliga attribut men vanligen genom klassnamn.variabelnamn public static void report() { System.out.println( "Antal skapade cirklar: " + nCircles ); } • Det går också att ha klass-metoder som alltså kan användas utan frikopplat från objekten (ex Math.sin() och main()) public static void main(String [] args) { Circle1 c; for ( int i = 1; i<=10; i++ ) c = new Circle1( new Point( 10*i, 15*i ), 5*i ); report(); } • En klassmetod kan inte referera objektattribut och ej heller anropa andra objektmetoder utan att gå via en objektreferens & % } & 49 ' $ % 50 $ ' $ Tecken Omslagsklasser import extra.*; • Till var och en av de primitiva datatyperna (byte, short, int . . . ) finns en omslagsklass (eng wrapper class) public class Tecken { public static void main(String [] args ) { int nUpper=0, nLower=0, nOthers=0; char c; • Klasserna har samma namn som de primitiva typerna men med inleds med en versal (de som hör till int och char heter dock Integer och Character) Std.out.print("> "); Std.out.flush(); while( (c=(char)Std.in.readChar()) != ’\n’ ) { if ( Character.isUpperCase(c) ) nUpper++; else if ( Character.isLowerCase(c) ) nLower++; else nOthers++; } Std.out.println( "Stora: " + nUpper + ", små: " + nLower + ", övriga: " + nOthers ); • Dessa klasser innehåller – Ett antal klass-attribut med konstanter (t ex max och minvärde) – Ett antal klass-metoder för t ex konverteringar – Ett antal instansmetoder för motsvarande för ett objekt } } & % 51 & % 52 ' Konvertering av objekt till String $ Man kan definiera omvandlig av objekt till typen String för t ex utskriftsändamål genom att definiera en metod toString() ' $ Fält Exempel Fält (arrayer) är ett slags objekt och hanteras således med referenser och har attribut och metoder. public class Circle { Point center; double radius; Deklaration // en massa metoder typ [] namn public String toString() { return "Circle(" + center + ", " + radius + ") "; } typ [] namn = fältreferens typ [] namn = {v0 , v1 , . . . vn } Skapas med public static void main(String [] args) { Circle c = new Circle( new Point(0.,0.), 1.0 ); System.out.println( c ); } new typ [antal ] eller, som en kopia av annat fält med } (typ[])fältreferens.clone() kursa$ java Circle Circle(Point@1fa4d404, 1.0) kursa$ & % & % 54 53 ' $ ' $ Fält med strängar Parametern till main är en array av strängar innhållade orden på kommandoraden: • Tilldelning = • Jämförelser == och != public class Echo { • Attributet length public static void main( String [] args ) { for ( int i = 0; i<args.length ; i++ ) System.out.print( args[i] + ’ ’ ); System.out.println(); } • System.arraycopy() • Klassen java.util.Arrays – equals – sort } – binarySearch kursa$ java Echo hej du glade! kursa$ & % 55 hej du & glade! % 56 ' $ Exempel public class Circles { Circle [] theCs; int nCs; ' $ En bättre add-metod public class Circles { public Circles() { nCs = 0; theCs = new Circle[5] ; } Circle [] theCs; int nCs; public void add(Circle c) { if ( theCs.length == nCs ) { Circle [] newArr = new Circle[2*theCs.length]; System.arraycopy( theCs , 0, newArr, 0, theCs.length ); theCs = newArr; } theCs[nCs++] = c; } public void add(Circle c) { theCs[nCs++] = c; } public static void main(String [] args) { Circles circles = new Circles(); Point p = new Point(0,0); for ( int i = 1; i<=10; i++ ) { circles.add( new Circle( p, 10*i ) ); } } } // övriga metoder kursa$ java Circles java.lang.ArrayIndexOutOfBoundsException: 5 at Circles.add(Compiled Code) at Circles.main(Compiled Code) kursa$ & % & 57 ' % 58 $ ' $ Exempel: Instickssortering Flerdimensionella fält public class InsertionSort { class Matrix { double [][] e; public static void sort( int [] a ) { int i, j; for ( i = 1; i<a.length; i++ ) { int x = a[i]; for ( j = i - 1; j>=0 && x<a[j]; j-- ) a[j+1] = a[j]; a[j+1] = x; } } public Matrix(int rows, int cols) { e = new double[rows][cols]; } public Matrix add(Matrix m) { int rows = e.length; int cols = e[0].length; // Borde kolla dimensionen ... Matrix p = new Matrix(rows,cols); for (int i= 0; i<rows; i++ ) for ( int j = 0; j<cols; j++ ) { p.e[i][j] = e[i][j] + m.e[i][j]; } return p; } public static void main(String [] args ) { int a[] = {5, 17, 3, 19, 10, 12, 2}; sort(a); for (int i= 0; i<a.length; i++ ) System.out.print( a[i] + " " ); System.out.println(); } } } & % 59 & % 60