Detta dokument förutsätter Netscape 4 eller Internet Explorer 4, om du har tidigare versioner klicka här.
import java.applet.*; import java.awt.*; public class Welcome extends Applet { public void paint( Graphics g) { g.drawString("Welcome to the World of Internet Programming", 100, 100); } };Detta program sparas i filen Welcome.java (observera att filnamnet måste vara identiskt med klassnamnet) som kompileras med kommandot
javac Welcome.javavarvid en fil (med suffixet .class) i s.k. bytekod skapas. Denna fil anropas sedan med hjälp av märkordet (eng. tag) APPLET från en web-sida:
<APPLET CODE="Welcome.class" WIDTH=500 HEIGHT=120> </APPLET>Man kan titta på (och debugga) sin applet på två sätt, endera med kommandot
appletviewereller i en nätbläddrare. Detta blir resultatet:
Nu finns det inte mycket dynamik i texten men Java är speciellt skapat för och därför mycket lämpligt för att generera grafik och användargränssnitt. Mer om det senare.
Det som händer när en nätbläddrare hittar ordet APPLET är att Java-programmet (eller snarare den bytekod som genereras av javac) laddas ned till klientmaskinen, d.v.s. den maskin som surfaren sitter vid. Detta kan verka farligt men en applet har mycket begränsade befogenheter och kan inte komma åt klientdatorn (surfarens dator) eller dess disk.
Java är ett objektorienterat programspråk. Vad detta innebär beskrivs i det följande.
Som vi har sett är Java ett objektorienterat språk. Vad innebär detta för
själva processen "att skapa ett program"? Svaret är att eftersom OOP ser
program som en samling av
Sammanfattningsvis: Objektorientering är att arbeta med modeller och att ställa problemområdet i centrum. I ett objektorienterat synsätt delas programmering in i fyra faser: analys, design, implementation och testning. Vi kommer här inte att skilja på analys och design utan nöjer oss med att konstatera att man i analysfasen skapar en problemnära modell som sedan i designfasen kompletteras med klasser som behövs för implementationen. Man bör hålla isär de två men i praktiken växlar man ofta mellan nivåerna: en analys följs av en design som ger upphov till förändringar i analysen, etc.
De viktigaste begreppen i OOP har grafiska motsvarigheter i OMT-notationen, t.ex. rektanglar för klasser och små trianglar för arv. En del av analysfasen går ut på att skapa en objektmodell med hjälp av dessa.
Man kan se en klass som ett record eller en datapost med operationer, d.v.s. funktioner som kan påverka klassen eller besvara frågor om den. Funktionerna kallas metoder och klassens data kallas dess attribut. En viktig del av OOP är att inga andra än klassens metoder kan ändra på data i klassens instanser.
En klass ritas som en rektangel (se figuren till vänster nedan).
I det inledande exempelprogrammet är Applet
en klass som
finns i Java
och Welcome
är en sorts
Applet
.
Arv visas med en triangel med den toppiga sidan uppåt mot superklassen:
Här har vi en superklass (kallas ibland basklass) som innehåller det som är gemensamt för de båda subklasserna, både attribut och metoder.
Det kan finnas klasser som inte är möjliga att instansiera, s.k. abstrakta klasser. En sådan klass tjänar endast som superklass till andra klasser och kan innehålla abstrakta metoder, d.v.s. metoder som inte implementeras i klassen men i de subklasser som kan instansieras (senare i detta avsnitt visar ett exempel på en abstrakt klass).
En association skall vara en fast relation, inte tillfällig. Tillfälliga relationer kan ofta bättre beskrivas som operationer (metoder).
En linje utan siffra eller ring betyder att multipliciteten är exakt 1, en fylld ring betyder många (noll eller fler), en ofylld ring betyder en eller ingen och en eventuell siffra anger alla tillåtna multiplicitetsvärden.
I figuren är associationen mellan Klass_1 och Klass_4 sådan att till varje Klass_1 skall en eller flera Klass_4 vara associerade. Varje instans av Klass_5 är associerad till 1,2,3,4 eller 8 instanser av Klass_2. Varje instans av Klass_3 är associerad till en eller ingen Klass_6, medan varje instans av Klass_6 har många Klass_3-objekt knutna till sig. Klass_3 skulle t.ex. kunna vara personer och Klass_6 yrke (om man nu antar att ingen i dessa arbetslöshetstider är ofin nog att ha flera jobb).
I OMT-notationen används olika sorters cirklar för att poängtera hur många instanser av en klass som kan relateras till en klass. Cirklar kan finnas i båda ändar av relationen. Om man, vilket man kan göra, anger multipliciteten med siffror är cirklarna strängt taget onödiga. I UML har man också tagit bort dem och anger 0.. i stället för fylld cirkel, 0-1 i stället för tom cirkel, o.s.v.
Som framgår av figuren finns det alternativa sätt att visa aggregatsrelationer.
Steg ett i analysfasen är att leta efter lämpliga objekt t.ex. genom att göra en lista med alla substantiv i problembeskrivningen (den traditionella algoritmbaserade programmeringstekniken utgår från verben). Först kan man tillåta sig att vara okritisk och ta med "allting", men innan man är klar måste man rensa bort ovidkommande saker och kanske göra de enklaste klasserna till attribut. Regeln är ungefär att de presumtiva klasser som inte behövs utanför en annan klass kan ses som attribut till denna andra klass.
Modellen byggs sedan ut genom att man letar efter associationer och arv. Exakt hur man går till väga är svårt att beskriva i ord. Men det är viktigt att man verkligen hittar arvsrelationer (tänk efter om en klass B är en sorts A) och associationer. Eftersom allting i Java är klasser (det finns inga "vanliga" funktioner) blir det ju inget program om man inte lyckas få sina klasser att hänga ihop.
Sista delen i analysfasen är att förfina sin design genom att lägga till operationer på klasserna. Här, liksom tidigare, är scenarier ett hjälpmedel
Att skapa en objektmodell är oftast ett iterativt arbete, d.v.s ett senare steg kan påverka tidigare modellen som då måste anpassas.
Programmet implementerar en del av ett ritprogram. För att inte det hela ska
bli alltför oöverskådligt har inte själva den interaktiva konstruktionen av
figurer tagits med utan appletens init()
-metod skapar ett antal
figurer som användaren kan flytta omkring, dels en och en (om man klickar med
musen nära centrum av en figur och med musknappen nedtryckt sedan flyttar
markören), dels också alla samtidigt (om man klickar någon annanstans).
Appleten följer här:
I objektmodellen är Shape
-klasserna mer detaljerade än de övriga
(det finns ju ingen mening i att lägga in Javas hela klasshierarki ovanför
Applet
t.ex. - vi anser Applet
vara superklass):
Notationen {abstract} kan användas för att särskilt markera att operationen draw är abstrakt och alltså måste implementeras i subklasserna.
De två klasserna MouseAdapter
och
MouseMotionAdapter
hanterar händelserna musklick och
musförflyttning (mer om hur detta går till
senare).
Hur skulle nu Shape
och dess subklasser implementeras i ett icke
objektorienterat språk? Det troligaste är något i stil med (i ett tänkt
Java-liknande språk där klasserna är enkla records som i Pascal eller C):
class Shape { int typeOfShape; int x,y,size; boolean fill; } Shape shape[MAXNUMOFSHAPES]; for (int i=0; i < numOfShapes; i++) draw( shape[i] ); draw ( Shape shape ) { switch (shape.typeOfShape) { case SQUARE: drawSquare( x, y, size, fill); case TRIANGLE: drawTriangle( x, y, size, fill); case CIRCLE: drawCircle( x, y, size, fill); } }Principen för hur det ser ut i Java:
class Shape { int x,y,size; boolean fill; draw(); } class Triangle extends Shape { draw() { rita triangeln; } } class Square extends Shape { draw() { rita kvadraten; } } class Circle extends Shape { draw() { rita cirkeln; } } Shape shape[MAXNUMOFSHAPES]; for (int i=0; i < numOfShapes; i++) shape[i].draw();Punkt-notationen används för metoder:
a.b()
innebär alltså att
metoden b
anropas för instansen a
och vi behöver
alltså inte skicka med a
som argument till b
.
De båda kodsnuttarna ovan är inte fullständiga och kan kanske tyckas likvärdiga
vid första anblicken. Men anta nu att man får ändrade förutsättningar, t.ex.
att man vill kunna rita rektangler eller ellipser. I den funktionsbaserade
lösningen krävs nu relativt omfattande ändringar: alla funktioner som
utför något - i exemplet endast draw()
, men många fler funktioner
finns i ett fullfjädrat ritprogram - måste ändras genom att nya
case
-satser läggs
in. Den objektorientade lösningen däremot tillåter att man lägger in kod för de
nya figurerna utan någon ändring alls av existerande kod:
Man kan lägga till nya figurer (rektanglar, ellipser,
månghörningar, etc) utan att någonting i det redan skrivna behöver
ändras eller ens kompileras om.
Lägg märke till att alla typer av figurer (som är subklasser till
Shape
) kan lagras i variabler av typen Shape
.
Olika figurer kan sedan "bete sig" olika när en metod anropas - detta kallas
polymorfi och är en mycket viktig del av objektorienterad
programmering. Programmeraren uppnår denna polymorfi genom att
ersätta (eng. override) metoder i superklassen:
man skriver helt enkelt en ny metod med samma signatur: samma namn
och samma parametrar. Abstrakta metoder måste "ersättas" i
subklasserna eftersom de inte är implementerade i superklassen.
En annan mycket stor fördel med OOP-lösningen är att man kan ändra den interna
representationen av formerna utan att program som använder
Shape
-klasserna påverkas. Detta kallas inkapsling
(eng. encapsulation) av data.
extends
för arv. Aggregat åstadkoms helt enkelt genom
att en klass innehåller variabler som refererar instanser av en annan klass, i
en array om multipliciteten är större än 1. Referenser används också för
associationer. I koden ser man alltså ingen skillnad mellan associationer och
aggregat, mer än att aggregat-delarna instansieras av klassen själv medan
associationerna oftast skickas i form av referenser till en metod - att
OOPExempel
själv skapar Shape
-objekten är ju en
följd av att själva konstruktörsmetoderna (eller kanske -objekten?) inte finns
med.