java.awt
för att skapa grafiska användargränssnitt. Klassen
Object
i paketet java.lang
är superklass till
samtliga Java-klasser.
java.net
, för
nätverksprogrammering. Detta innehåller klasser för att skriva klient-
och server-applikationer.
Det faktum att Java är interpreterat innebär att program i Java inte är lika snabba som t.ex. program i C, men dagens applikationer är nästan alla interaktiva och/eller nätverksbaserade och befinner sig mestadels i väntetillstånd. Dessutom finns till många system numera s.k. just-in-time (förkortningen JIT avser just detta) kompilatorer som kompilerar bytekoden till maskinkod just innan ett program körs.
boolean
. Till skillnad
från de flesta andra språk definierar Java exakt storleken på alla inbyggda
typer. Alla Java-variabler har default-värden, d.v.s. värden som variabler
som ej har getts ett värde får.De inbyggda typerna är, med angivande av storlek i bit och default-värde:
char
är alltså inte 8 bits utan varje
tecken är en 16-bit Unicode kod. Vi programmerare behöver
normalt inte tänka på detta: klassen String
inkapslar
stränghanteringen i Java - dessutom är de 256 värden som kan representeras i
en byte identiska i ASCII-koden och Unicode-koden. Alla de numeriska typerna
har tecken.
class Circle { public int r; public int x; public int y; public move( int dx, int dy ) { x += dx; y += dy; } }Denna klass har attributen
r
, x
och
y
samt metoden move()
.
Nyckelordet public
anger att klassens användare kan komma åt
allting. Datafält och metoder koms åt med hjälp av punktnotation: t.ex.
circle.r
eller circle.move(-10,-10)
om
circle
är ett objekt av klassen Circle
.
null
(default) som betyder att variabeln inte refererar något
eller också refererar variabeln en
klassinstans. Eftersom Java är ett s.k. hårt typkontrollerat språk kan en
viss variabel bara referera instanser av en viss klass (se dock avsnittet
Arv för en mer nyanserad bild av verkligheten)Skillnaden mellan de inbyggda typerna och referenser är att de förra hanteras by value, d.v.s. en kopia av variabeln överförs vid metodanrop, medan referenserna hanteras by reference, d.v.s endast adressen överförs.
I Java räcker det inte med att deklarera en variabel för att skapa ett objekt, man måste explicit skapa objektet med new:
Circle a; // skapar tom referens a = new Circle(); // skapar ett Circle-objekt Circle b = new Circle(); // skapar både referens och objekt.En tom referens har värdet
null
som alltså betyder att variabeln
inte refererar någonting. Ordet null
är reserverat i Java.
Objekt av klassen String
kan skapas genom uttryck som
String s = "Detta är en sträng";Man kan alltså (och bör så ofta som möjligt) ge variabler värden direkt vid deklarationen. Detta gäller både de inbyggda typerna och klassinstanser. Något som skiljer Java från de flesta programspråk (men inte C++) är att variabler kan deklareras "var som helst", d.v.s. exekverande satser och deklarationer kan blandas.
Variabler existerar bara i det block de deklareras, d.v.s. från
deklarationstillfället till nästa }
:
{ Circle a(10); { Circle b(20); b.draw(); } // a finns här, men inte b: a.draw(); - ok b.draw(); - fel }I Java allokeras minne för alla objekt dynamiskt. Till skillnad från t.ex. C++ och C behöver man inte återlämna minne, Java har automatisk s.k. "garbage collection", d.v.s. ett objekt som inte längre behövs (inte har någon variabel som refererar till sig) tas automatiskt bort. Att Java saknar pekare i traditionell mening och dessutom saknar konstruktioner för att återlämna minne kan te sig konstigt om man tidigare programmerat i C, C++ eller Pascal t.ex. men detta är faktiskt något som underlättar programmeringen och undanröjer en mycket vanlig felkälla.
int[] intBuf = new int[1024]; Circle[] circles = new Circle[10]; double[] doubleTabl = { 1.0, 1.5, 2.0, 3.0, 6.0 }; int[][] twoDArray = new int[8][8];Arrayers element initieras med respektive typs defaultvärde, i fallet objekt alltså med
null
, d.v.s. inga Circle-objekt skapas i
exemplet, endast 10 st. tomma referenser. Man kan också som i exemplets
doubleTable
ge arrayens element värden direkt i deklarationen.Observera att i Java, till skillnad från C++, kan man direkt dynamiskt allokera flerdimensionella arrayer. Java implementerar multidimensionella arrayer som arrayer av arrayer varför man, liksom i C++ och C, kan skapa ickerektangulära arrayer:
int[][] strange2Darray = { {5,6}, {3}, {3,4,5} }; double[][] triangular = new double[10][]; // triangular array: x for (int i=0;i < 10; i++) // xx double[i] = new double[i+1]; // xxx ...Man kommer åt elementen i en array på vanligt sätt:
int i = strange2Darray[0][1]; int j = intBuf[123];Som i C och C++ är index för första elementet 0. Java kontrollerar alltid att index håller sig i tillåtet område, annars "kastas ett undantag", se Undantag.
Varje array har ett fält, length
som talar om hur många element
den innehåller:
int[] a = new int[10]; int[][] b = new int[10][5]; int[][][] c = new int[5][6][4]; // // a.length = 10 // b.length = 10 // c.length = 5 // c[3].length = 6 // c[3][3].length = 4 //
Object
:
Vector
. En Vector
har ingen
bestämd storlek utan växer efter behov. Eftersom s.k. operatoröverlagring
(möjligheten att överlagra operatorer som +, -, etc.) ej finns i Java kan
man inte använda []-syntaxen för elementåtkomst i en Vector
.
I stället finns en mängd metoder, t.ex. elementAt
för
manipulering av enskilda element.
new
skriver man något
som ser ut som ett metodanrop:
Circle = new Circle(); Circle = new Circle( 10, 100, 150):Det är också vad som sker, systemet anropar en s.k. konstruktor, en metod som initierar objektet enligt parametrarna. Observera att i Java kan man inte skriva t.ex.
Circle = new Circle;
som man kan i C++,
uttrycket efter new
måste alltid se ut som ett metodanrop.
Normalt skriver man en eller flera konstruktorer men gör man det inte skapar
Java en s.k. default-konstruktor utan argument som inte gör någonting. Man
kan skriva flera konstruktorer med olika parameteruppsättning, s.k.
överlagring (eng. overload, observera skillnaden mellan
overload och override).
Exempel på en klass med konstruktor:
class Circle { public Circle( int ir, int ix, int iy ) { r = ir; x = ix; y = iy; } private int r; private int x; private int y; }Här har attributen deklarerats
private
vilket beyder att endast
klassens metoder kommer åt dem.
Om man skriver en metod som heter
void finalize()
kommer denna
att anropas när objektet inte längre refereras men innan objektets minne
återlämnas. Oftast behöver man ingen sådan metod men ibland kan man behöva
återlämna någon systemresurs som inte Javas skräphanterare tar hand om.
struct
i C: man kan initiera attribut (och läsa
och ändra dem om de är deklarerade public
). Låt oss titta litet
mer på en klass som beskriver en rektangel:
class Rectangle { public Rectangle( int ix, int iy, int iw, int ih) { x = ix; y = iy; w = iw; h = ih; } public Rectangle( int ix, int iy, int side ) { x = ix; y = iy; w = side; h = side; } public int area() { return w * h; } private int x; private int y; private int w; private int h; }Här ser vi exempel på överlagrade konstruktorer och dessutom en metod som beräknar rektangelns yta. Metoden
area()
är en s.k.
instansmetod, en metod som (med hjälp av punktnotation) anropas med
en klassinstans.
Rectangle r = new Rectangle( 500, 500, 200, 300); int ytan = r.area();I en metod kan man referera "sig själv" med
this
. Man skulle
t.ex. kunna skriva instansmetoden area()
så här:
public int area() { return this.w * this.h; }Nu gör man naturligtvis inte så men det finns tillfällen när
this
verkligen behövs, nämligen när man behöver skicka en referens till sig
själv till en metod i en annan klass. Man kan också använda this
för att anropa en annan konstruktor, t.ex:
public Rectangle( int ix, int iy, int side ) { this(ix,iy,side,side); }De flesta metoder är instansmetoder, men det finns också s.k. statiska metoder (eller klassmetoder). Antag t.ex. att man vill kunna räkna ut ytan på en rektangel utan att skapa ett objekt. Då är en klassmetod ett alternativ:
public static int area( int w, int h ) { return w*h;}Man kommer åt statiska metoder genom klassnamnet:
int area = Rectangle.area(5,4);Det är nyckelordet
static
som anger att metoden är en klassmetod.
Anledningen till att man skriver area()
som klassmetod i klassen
Rectangle
är att endast denna klass bör veta hur en rektangels
yta beräknas (inkapsling inte bara av data utan också av metoder).
Även attribut kan vara statiska, i vårt exempel kan man tänka sig att man vill flytta alla rektanglar likadant (translatera dem). Ett sätt att implementera den möjligheten är att deklarera en par klassattribut:
private static int dx=0; private static int dy=0;Som synes kan man också ge initialvärden till statiska attribut. Dessa initieras när klassen laddas. Initialvärden kan också ges till vanliga instansattribut: dessa initieras när instansen skapas. Oinitierade attribut ges defaultvärden av kompilatorn.
Liksom i fallet med konstruktorer kan man överlagra metoder, d.v.s.
skriva flera metoder med samma namn men med olika parameteruppsättningar, t.ex.
kan man i fallet Rectangle
tänka sig en klassmetod som
beräknar en kvadrats yta:
public static area( int side) { return side*side; }Eftersom Java inte har funktioner i vanlig mening är statiska metoder vanliga: de kan ju nästan ses som "vanliga globala funktioner". En del klasser har bara statiska metoder, t.ex. klassen
Math
. Några av dess
deklaration och exempel på användning:
class Math { public static final double E = ...; // konstanten e (2.718...) public static final double PI = ...; // konstanten pi (3.142...) public static double sin(double a) { .. } public static double cos(double a) { .. } public static double sqrt(double a) { .. } public static double exp(double a) { .. } public static double pow(double a, double b) { .. } } double a = Math.sqrt( 1.2); double cirkelyta = 2 * Math.PI * radius;Ännu en modifierare till attribut,
final
, dyker upp i Math. Detta
är Javas konstantdeklaration, E
och PI
får inte
ändras.
De operatorer som opererar på referenser (objekt) är (alla utom '+' opererar på samtliga typer av objekt):
(type) - cast operator, se vidare nedan i avsnittet om arv. + - med String-objekt som operander - strängsammanslagning == - likhet (de båda operanderna refererar samma objekt) != - ej likhet (de båda operanderna refererar ej samma objekt) = - tilldelningExempel på användning:
Shape a = new Circle(); Circle b = (Circle) a; String b = "Kalle " + "Anka"; Circle c; if (a==b) c = a; // likhet och tilldelning if (a!=b) c = new Circle(); // olikhet och tilldelningUttrycket
c=a
i exemplet betyder att c kommer att referera samma
objekt som a (eller inget objekt alls om a har värdet null
).
Om man verkligen vill kopiera objektet kan man använda metoden
clone()
. Metoden equals()
används för att ta reda
på om två objekt är lika:
if (a.equals(b)) c = a.clone(); // riktig likhet och riktig tilldelning
String
. Genom att representationen av strängar göms här
behöver man som programmerare inte bry sig om hur tecken lagras (d.v.s. att
Unicode används i stället för ASCII). Några exempel på användning visar
bäst klassens metoder:
// // Användning av klassen String. // String a = "detta är en sträng "; int i = 324; a = a + i; // a = "detta är en sträng 324" String b = a.substring(9, 18); // b = "en sträng" String c = a.substring(9); // c = "en sträng 324" (till slutet) char d = a.charAt(0); // d = 'd' int p1 = a.indexOf('e'); // p1 = 1 (första 'e') int p2 = a.indexOf("ng"); // p2 = 16 (första "ng") int l = a.length(); // l = 22Observera att metoden
substring(startindex,endindex)
returnerar
en sträng som börjar i startindex
och slutar i
endindex-1
.
Klassen String
har metoder för konvertering av tal till sträng.
Metoderna är överlagringar av varandra och heter
public static String valueOf(typ)
där typ är en av de inbyggda typerna.
Strängar av klassen String
får inte ändras. Om man
vill kunna ändra i en sträng kan man använda klassen
StringBuffer
i stället:
// // Användning av klassen StringBuffer // StringBuffer a = new StringBuffer("detta är en sträng "); int i = 324; a.append ( i); // a = "detta är en sträng 324" a.setCharAt( 0, 'D'); // a = "Detta är en sträng 324" a.insert(9, "inte "); // a = "Detta är inte en sträng 324"Metoderna
append()
och insert()
är överlagrade för
alla typer: String.valueOf()
används för konvertering till sträng
(valueOf()
i sin tur använder toString()
om
argumentet är en instans av en klass).
Vector
-objekt eller man vill kanske kunna utföra en operation på
en double.För detta ändamål finns i Java till varje inbyggd typ en motsvarande typklass:
TYP TYPKLASS boolean Boolean byte Byte char Character double Double float Float int Integer long Long short ShortAlla typklasser har följande konstruktorer och metoder (där Typklass är en typklass och typ själva typen):
Typklass( typ v); // ex: Integer a = new Integer(12); Typklass( String s); // ex: Double d = new Double("123.45"); String toString(); // konvertera till sträng, ex: String a = a.toString(); typ typValue(); // returnerar värdet, ex int i = a.intValue(); boolean equals(typ v);// sant om de två objekten har samma värde.Typklasserna innehåller alltså metoder för konvertering mellan tal och strängar. Metoden
toString()
anropas automatiskt i uttryck som
t.ex.
Integer a = new Integer(10); String s = "Value of a is " + a; System.out.println( "Value of a is " + a );Utskrift till terminalfönstret av strängar görs med anrop till
System.out.println
med en sträng som parameter. Faktum är att
även vanliga tal, som inte lagras i en instans av en typklass, konverteras på
samma sätt och med samma metod.
toString()
. Om man
skriver egna klasser bör man skriva toString
(egentligen
överlagra eftersom metoden finns i Object
) så får man samma
uppförande som de inbyggda typerna har.
Javas satskonstruktioner liknar mycket C++. I detta avsnitt visas med exempel samtliga konstruktioner som finns i språket utom de som har med undantag att göra.
int i=0; . if (i > 0) i++; else i--;Skillnaden mellan Java och C/C++ är att villkorsuttrycket i Java måste vara av typen
boolean
. Värdena 0
och
null
t.ex. har inte värdet falskt utan man måste skriva
"if (anObject!=null) {}
" och "if (a!=0) {}
".
int i; for (i = 0; i < 10; i++) System.out.println( i ); for (int j=5; j >= 0; j--) {} for (int i=0, j=100; i < 100; i++, j-=5) {}Exemplen visar de vanligaste formerna av
for
-loopen. Observera att
man kan göra flera saker i initierings- och inkrementeringsdelarna av loopen
genom att använda komma.Viktigt att veta är att variabler som deklareras i initieringsdelen existerar bara inne i loopen, inte efteråt.
int i = 10; while (i > 0) { Shape a = firstShape(i); if (a != null) do { a.do_it(); a = nextShape(a); } while (a != null); i--; }Dessa konstruktioner ser ut som i de flesta programspråk. Viktigt att komma ihåg är att vi måste testa explicit mot 0 och
null
i
villkorsutrrycken.
switch ( i ) { case 1: i += 123; break; case 3: i += 456; break; case 5: i += 789; break; default: i = -1; break; }Variabler av typerna
byte
, char
, short
,
int
och long
är tillåtna som
case
-labels. Notera att break
är nödvändigt för
att inte fortsätta exekveringen med nästa case
.
break
och continue
används på samma
sätt som i C/C++ med tillägget att man kan hoppa flera nivåer med hjälp av
etiketterade break
och continue
. Man bör vara
sparsam med användandet av dessa båda satser eftersom de ofta leder till
svårläst och svårunderhållen kod; inga exempel förutom i switch
ges.
Java är ett generellt programspråk som kan användas också för applikationer
utanför Internet. Skillnaden mellan en applet och en applikation ligger i
hur och av vem programmen startas: en applet startas av en nätbläddrare
medan en applikation startas i en speciell metod som heter
main()
. Flera av de klasser som tillsammans utgör en applikation
kan innehålla main()
-metoder: programmet startas i den
main()
som finns i den klass som anges på kommandoraden.
En applet å andra sidan administreras och körs av nätbläddraren. Programmeraren
skapar en applet genom att skriva en subklass till Applet
och
ersätta en eller flera av följande metoder:
Mer om hur man använder metoderna kommer i avdelningen om
trådar. Metoden paint()
är inte
appletspecifik utan används av alla GUI-komponenter (se vidare avsnittet
Java AWT och händelsehantering).
Oavsett om man har skrivit en applet eller en applikation kompileras programmet med javac:
javac myclass.javaEn applikation startas sedan genom att man ger kommandot
java
följt av namnet på den klass man vill starta i (en klass som har en
main
-metod):
java myclass.class
medan appleten startas med appletviewer eller i nätbläddraren på det sätt vi
tidigare visat.
import java.applet.*; import java.awt.*; public class WelcomeApplication extends Applet { public static void main( String[] args ) { WelcomeApplication wapp = new WelcomeApplication(); Frame frame = new Frame("Welcome"); frame.add(wapp); frame.setSize( 500, 200); wapp.init(); wapp.start(); frame.show(); } public void paint( Graphics g) { g.drawString("Welcome to the World of Internet Programming", 100, 100); } };Metoden
main()
skapar en instans av appleten,
ett fönster (en Frame
)
att visa den i, placerar appleten i fönstret (metoden add
),
definierar fönsterstorleken, anropar init
och start
(som nätbläddraren annars skulle ha gjort), samt visar fönstret.
Lägg märke till att main()
är en
klassmetod (static
) som inte
returnerar någonting. Argumentet är en array av strängar - de argument som
gavs på kommandoraden efter klassens namn. Eftersom ingenting kan returneras
från main()
kan man inte returnera ett värde till systemet
den vägen: använd
System.exit(n)
där n är det du vill returnera om du
måste meddela systemet något.
Applikationen ovan saknar någonting viktigt: den går inte att avsluta! Nästa avsnitt handlar om AWT (Abstract Windowing Toolkit) och hur man tar hand om användarens önskemål.
<APPLET>
:
<APPLET CODE="filnamn" WIDTH=pixelbredd HEIGHT=pixelhöjd CODEBASE=appletdirectory ALIGN=sidplacering> <PARAM NAME=parameter VALUE=värde> </APPLET>(dessa är de vanligaste kommandona, det finns fler)
Man måste alltid ange CODE
, WIDTH
och
HEIGHT
, resten kan utelämnas. CODEBASE
skall vara
den katalog där appleten ligger, inte själva appleten. Om
CODEBASE
utelämnas används den katalog där det refererande
dokumentet finns.
Nyckelordet PARAM
kan förekomma många gånger, där varje
förekomst svarar mot ett parameternamn med värde. Parametrarna kan läsas av
appleten, se exemplet Scribble
).
Metoden getParameter( String par )
returnerar värdet av
parametern par
i form av en sträng.