Programmering Java Fördjupning
 9789175310213, 917531021X

Citation preview

Till denna bok medföljer ett antal övningsfiler som du laddar ner från vår webbplats www.docendo.se: 1. Starta webbläsaren, skriv www.docendo.se i adressfältet och tryck på Retur. 2. Skriv artikelnumret, 1260, i sökrutan och klicka på Sök. 3. Klicka på titeln Programmering Java Fördjupning. 4. Klicka på filen 1260.zip högst upp på sidan. 5. Klicka på Spara, välj var du vill spara filen, exempelvis på skrivbordet, och klicka på Spara. 6. När filen har hämtats stänger du dialogrutan och avslutar webbläsaren. 7. Om du har valt att spara filen på skrivbordet visas den som en ikon med namnet 1260. Dubbelklicka på ikonen för att packa upp filerna till lämplig mapp på din hårddisk.

Copyright © Docendo AB Detta verk är skyddat av upphovsrättslagen. Kopiering, utöver lärares rätt att kopiera för undervisningsbruk enligt BONUS-avtal är förbjuden. BONUS-avtal tecknas mellan upphovsrättsorganisationer och huvudman för utbildningsanordnare, exempelvis kommuner/universitet. Våra böcker och tillhörande produkter är noggrant kontrollerade, men det är ändå möjligt att fel kan förekomma. Vi tar gärna emot förbättringsförslag. Produkt- och producentnamnen som används i boken är ägarens varumärken eller registrerade varumärken. ISBN: 978-91-7531-021-3  Artikelnummer: 1260E Författare: Jonas Byström Redaktör: Iréne Friberg Omslag: Malina Andrén Bild på omslaget ©iStock

1

Repetition och lite nytt

I detta kapitel A-kursen repeteras här i komprimerad form i sina huvuddrag. Du förutsätts förstå grundläggande Java samt kunna hantera någon utvecklingsmiljö för Java, till exempel NetBeans.

Programexekvering Ett program exekveras ”uppifrån och ner”. Centralprocessorn (CPU:n) läser och utför maskinkoden instruktion för instruktion, på samma sätt som Java-VM (Virtual Machine) läser och utför bytekod. Java-VM ger dessutom utvecklaren en ”sandlåda” att jobba i.

Loop Somliga instruktioner används för att flytta programexekveringen. Dessa instruktioner säger alltså åt Java-VM att läsa och utföra programkod på ett nytt ställe — vilket kan användas för att skapa loopar (även kallade slingor). En loop är när en viss del av koden utförs flera gånger; loopen utförs till dess ett visst uttryck är falskt. Start

Ja

Har du roligt? Nej Sov på saken!

Detta är ett exempel på en loop. Loopen utförs så länge uttrycket ”Har du roligt?” = ”Ja” är sant. Dock tröttnar ju alla någon gång, vilket leder till att uttrycket ”Har du roligt” = ”Ja” blir falskt. Detta i sin tur innebär att exekveringen går vidare till ”Sov på saken!”. Loopar används till att utföra samma operationer flera gånger, ofta en gång per dataelement. Till exempel är en loop ett idealiskt hjälpmedel för att söka igenom en lista.

5

1 Repetition och lite nytt

Källkod Källkod är den text du skriver in i din utvecklingsmiljö. Efter att du programmerat färdigt låter du en kompilator översätta Java-källkoden till bytekod som kan köras av Java-VM:en. Källkoden för större projekt organiseras i flera källkodsfiler. Filtillägget .java används för källkod, och de filerna innehåller klasser, metoder, interface eller variabler För att kunna skapa objekt av andra klasser så måste filen importeras. Detta gör du med import mitt_paket.MinKlass.

Verktyg I detta material har vi valt utvecklings-verktyget NetBeans IDE 7.2 (NetBeans) som exempel. Bilder, exempel och instruktioner i detta kapitel visar NetBeans. Om du arbetar i en annan version eller någon annan utvecklingsmiljö kan du ändå känna igen dig och göra övningarna. I NetBeans kan du lätt få hjälp om nyckelord och metoder genom att ställa markören i det ord du undrar över och sedan trycka Alt+F1. Prova gärna detta, till exempel med metoden System.out.println. I hjälpen kan du se vad den gör (Prints a String and then terminate the line) och se vad den har för parametrar, returvärde och andra relevanta fakta.

Säkerhetskopiera Börja med att kopiera övningsfilerna som medföljer materialet. Det bästa är om du hela tiden arbetar med lokala kopior. Lägg exempelvis källkoden någonstans under Mina dokument; lämpligt är kanske den mapp som skapas automatiskt av NetBeans vid installationen, mappen NetBeansProjects, om det är lämpligt för dig skapar du också en ny mapp kallad Java B till vilken du kopierar övningsfilerna.

Öppna, kompilera, kör och stäng Du ska nu öppna ett färdigt projekt för att direkt komma in i arbetsgången igen. Du ska börja med att starta utvecklingsverktyget. 1. Klicka på knappen Start, välj Alla Program, NetBeans, välj NetBeans IDE 7.2. När programmet startar kan det se ut som i följande bild.

6

1 Repetition och lite nytt

2. I menyn väljer du File, Open, Project... 3. Klicka på Phantom och klicka sedan på knappen Open Project. 4. Kompilera med F11. 5. Kör programmet med F6. En meddelanderuta visas:

6. Avsluta programmet genom att stänga meddelanderutan. 7. Avsluta NetBeans med File, Exit. Om det är några oklarheter så kan du alltid gå tillbaka till ”På rätt kurs: Java Programmering A” för att repetera; där finner du många och utförliga instruktioner för hur du ska gå tillväga vid hanteringen av NetBeans.

7

1 Repetition och lite nytt

Auto-importera Om du någon gång skriver in funktionalitet som du inte ännu har importerat så kommer du att få kompileringsfel. I stället för att manuellt skriva in ditt importuttryck högst uppe i Java-filen så kan du alltid trycka Ctrl+Shift+I för att lägga till import-uttrycket automatiskt. Detta är extremt användbart, lär dig detta utantill!

Programexempel Data och variabler Variabler är till för att lagra data i. Heltalsvariabler kan endast lagra heltal, flyttalsvariabler klarar tal i potensform. Heltalsvariablerna heter byte, short, int och long för 8-, 16-, 32- respektive 64-bitars heltal. Flyttalsvariablerna heter float och double. En array (eller ett fält) med variabler är när flera variabler ”ligger på rad” i minnet. En array med char kan omtolkas som en sträng, där varje enskilt tecken motsvarar en bokstav. En sträng deklareras med texten omgiven av citationstecken, till exempel ”Derivatan av en kvot är inte ofta konstigare än personen som deriverar”. Tilldelning till variabler anges med =, till exempel int x = 7;. Vid jämförelse används , =, == och !=, som exempel returnerar x < 5 sant om x är mindre än 5, falskt om x är större än eller lika med 5. Enkla, ”atomära”, datatyper som heltal och flyttal kopieras, medan mer komplex data refereras i stället. Referenser används alltså till att referera till data eller objekt. Mer repetition om referenser senare i materialet. För addition av variabler används operatorn +, subtraktion har operatorn –, multiplikation använder *, / används för division och % för modulus. Variabler kan deklareras antingen som medlemmar eller som lokala i en metod. Medlemsvariabler deklareras utanför alla metoder, och kan användas av alla metoder. Lokala variabler deklareras inuti en metod och kan bara användas i just den metoden. Så många variabler som möjligt ska vara lokala för att programmet ska bli lättläsligt och lätt att avlusa. För att skapa objekt används class, alternativt enum. enum används för att skapa representationer av olika status, till exempel LEFT, RIGHT, MIDDLE.

Några nyckelord

Nyckelordet if används för att villkorligt utföra ett antal satser. Nyckelorden do, while och for används alla för loopar.

8

1 Repetition och lite nytt

int x; for (x=1; x data[j+1]) { int temp = data[j]; data[j] = data[j+1]; data[j+1] = temp; } } } }

Uttrycket i if-satsen på raden under kommentaren avgör om listan kommer att sorteras i stigande eller fallande ordning. I detta fall byter elementen plats om värdet i elementet j är större än värdet i elementet j+1, vilket medför att listan kommer att sorteras i stigande ordning med minsta värdet först. Om ett - och cd LoadImage C:\JavaB\Kod\LoadImage>_

3. Starta programmet genom att ange något som kallas ”classpath”, det används som en sökväg för att hitta alla filer som laddas. Skriv in följande (på en rad): java -cp ”build/classes;../Sdb/dist/Sdb.jar” loadimage/ LoadImage



Sdb.jar är en arkivfil som innehåller Java-klasserna för att öppna fönster, och så vidare. På samma sätt måste du göra med ditt program för att kunna använda dig av sdb-paketet.

56

9

Java Generics

Inbyggda listor i Java Den funktionalitet du tidigare utvecklat med sortering, listor och hashtabeller finns inbyggd i Java. För att underlätta för användaren så kan man använda vilka klasser som helst, så att man slipper specialanpassa algoritmer eller datastrukturer för speciella ändamål. För att använda en inbyggd lista av strängar så gör man så här: List minLista = new ArrayList();

Notera att ArrayList ärver av List. För att lägga till och ta bort element så gör man så här: minLista.add(”En liten text”); minLista.add(”... och en till”); minLista.remove(1); // Ta bort andra elementet. String s = minLista.get(0); // Hämtar första.

Detta kallas Java Generics och förenklar storeligen användningen av listor, som synes, samt förbättrar prestanda avsevärt. Sortering är också enkelt på dylika listor: Collections.sort(minLista);

Även hashtabeller finns färdigt att använda: HashSet minHashTabell; minHashTabell = new HashSet(); minHashTabell.put(”Första”, 1); minHashTabell.put(”Andra”, 2); // Hämta ett elementet med angiven nyckel: Integer i = minHashTabell.get(”Första”);

Du behöver inte kunna detaljerna utantill för att klara av materialet, men det kan vara bra att känna till eftersom det senare kommer att komma exempel som innehåller Java Generics.

57

9 Java Generics

Övningsuppgifter Övning 9.1

Skapa en lista för att stoppa in heltal i. Man kan inte använda atomära typer i Generics, men det finns en klass som heter Integer...

Övning 9.2

Se om du kan använda klassen HashMap för att stoppa in värdet Göteborg med heltalsnyckeln 31, Stockholm med nyckeln 8 och Malmö med nyckeln 40. Du behöver ange två klasser för att definiera en instans av HashMap.

58

10

Praktisk programmering – TCP/IP och trådar

I detta kapitel Praktisk programmering mot TCP/IP ger några handfasta exempel på hur du kan använda färdig teknik för att göra din applikation mer intressant. Användning av TCP/IP är mycket vanligt i programvaruindustrin, vilket gör det så mycket mer attraktivt att lära sig. Kommunikation mellan datorer sker oftast med protokollet TCP/IP. Det är detta protokoll som används när du surfar, laddar hem filer, läser e-post, chattar, spelar multiplayer-spel, lyssnar på musik över nätet, et cetera. Den största programmeringsstandarden för att, med TCP/IP, koppla upp, skicka och ta emot data och koppla ner heter BSD Sockets. (Berkley Software Distribution Sockets är en standard från Berkley Unix.) Överhuvudtaget har denna standard bevarats förhållandevis väl, även på Microsofts plattformar. I Java medföljer ett antal klasser för att ytterligare förenkla kommunikationen via sockets, som du nu kommer lära dig använda. Du kommer även att beröra trådar i detta kapitel. Det är ett avancerat koncept som du kan använda för att exekvera flera saker samtidigt i ditt program.

Sockets Sockets fungerar ungefär som att öppna, läsa, skriva och stänga en fil. Dock brukar man säga koppla upp, läsa, skriva respektive koppla ner när det gäller nätverksanslutningar i stället för filer.

Telefonera och ringa upp En vanlig och mycket god analogi med sockets är den gamla hederliga telefonen. För att kunna ringa så måste du installera din telefon. I Java gör man det med följande konstruktor: Socket(String host, int port)

Socket använder det underliggande protokollet TCP, om du vill använda till exempel UDP så finns andra klasser för det. Hur gör man då för att koppla upp sig? Socket socket = new Socket(”google.com”, 80);

Den sista parametern är portnummret (till exempel port 80 för webservrar).

59

10 Praktisk programmering – TCP/IP och trådar

Du kan även ange en IP-adress direkt. IP-adresser består av ett tal på formen a.b.c.d där a, b, c och d är heltal mellan 0 och 255. Dessutom åtföljs alla TCP/IP-adresser av ett portnummer mellan 0 och 65535. Att man använder olika portnummer gör att man kan ha flera parallella uppkopplingar (surfa, e-post, chatt, och så vidare) på en dator, trots att man bara har ett IP-nummer. IP-nummer och TCP-port skrivs ofta ihop, så här: 1.2.3.4:56789; vilket alltså blir IP-adress 1.2.3.4 och TCP-portnummer 56789. För att lägga på telefonluren när du är klar så använder du funktionen close. socket.close();

Prata

Använd klassen PrintWriter för att skicka data: PrintWriter out = new PrintWriter( socket.getOutputStream(), true); out.prinln(”Hej från mig!”);

PrintWriter funkar på samma sätt som System.out, som du är van att skriva ut text med.

Lyssna

Om du vill ta emot data via en socket så använder du BufferedReader på samma sätt som för en fil. InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr); String line = reader.readLine(); System.out.prinln(line);

Vänta på samtal Om du vill att programmet ska vänta på att någon kopplar upp sig mot det (serverapplikation) så använder du klassen ServerSocket: ServerSocket serverSocket = new ServerSocket(12345); Socket clientSocket = server.accept();

Här lyssnar servern på porten 12345; detta motsvaras ungefär av att lyssna till en specifik telefon. När sedan någon kopplar upp sig är det bara att använda clientSocket som tidigare för att skicka och ta emot.

60

10 Praktisk programmering – TCP/IP och trådar

Om chattprogram Ett chattprogram är egentligen två olika program: ett klientprogram och ett serverprogram. För att du ska få någon slags meningsfull kommunikation så är det ju fördelaktigt om flera klienter kan koppla upp sig mot samma server – så kul är det ju inte att chatta med sig själv!

Server-/klientmodell Servern kommer att ha en lista med alla som är uppkopplade. Klienten skickar textdata som servern tar emot. Servern skickar den sedan vidare till alla uppkopplade klienter. I följande bild visas ett nätverksdiagram över flödet med fyra uppkopplade klienter:

Klient3

Klient1

2 2

1

Klient2

Server

2

2

Klient4

Klient1 skickar här ett meddelande (1) till Server. Server tar emot meddelandet, lägger på namnet ”Klient1: ” i början på meddelandet och skickar ut det till alla klienter (2).

Ett exempel förenklar: om Arne, Berit och Caesar är anslutna till en server och Arne skickar strängen ”Hejsan tjejen och killen!” till servern så ska alltså servern skicka ”Arne: Hejsan tjejen och killen!” till alla anslutna klienter, det vill säga till Arne, Berit och Caesar. När klienten tar emot ett meddelande från servern så ska det bara skrivas ut i klartext på skärmen. Programmet kommer att bli så enkelt som möjligt, ingen säkerhet mot flooding eller liknande DoS-attacker, ingen funktionalitet för kick eller ban (längre fram ges en förklaring till uttrycken). Dessa förslag på utökningar blir en extrauppgift för den engagerade. Uttrycken flooding, DoS-attacker, kick och ban är engelska. De används ofta i samband med nätverksprogrammering.

61

10 Praktisk programmering – TCP/IP och trådar

Flooding (översvämning) betyder att någon illvillig person skickar massor av nonsensdata till en annan dator. Denna dator får problem eftersom den inte hinner med att ta emot all inkommande data på ett korrekt vis. DoS står för Denial of Service. Ta flooding mot en chattserver som exempel. Säg att det finns 100 anslutna klienter till chattservern. En av dessa klienter har skapat en egen klientapplikation som skickar massor av textmeddelanden till servern som servern i sin tur försöker skicka vidare till alla anslutna klienter. Detta leder till två problem: 1) alla klienter får skräptext som de inte vill läsa och 2) servern måste skicka ut 100 gånger mer data än vad den hemmagjorda klientapplikationen skickar in. Man kan lätt inse att chattservern snart går på knäna i ett dylikt scenario. Kick kan vara ett kommando som serveroperatören använder sig av för att sparka ut oönskade klienter från servern. Det enda som sker är egentligen att klienten kopplas från. Ban (på svenska ungefär ”bannlysa”) används ofta också som ett kommando av serveroperatören. En bannlysning fungerar helt enkelt så att klienten kastas ut (kick) och sedan sätts en begränsad eller obegränsad tid till dess att klienten får tillstånd att logga in igen. En bannlysning kan ske antingen på IP-adressen eller på användarkontot (om sådant finns). Idén är helt enkelt att användaren ska få lite tid att tänka över sina onda handlingar innan tillfälle ges att utöva dem igen...

Kort om trådar Trådar är ett avancerat begrepp som har med parallellprogrammering att göra. Parallellprogrammering innebär att man låter datorn utföra två uppgifter simultant. Detta är egentligen inget konstigt – du använder det varje gång du har två program igång samtidigt. En tråd är en exekverande enhet inom ett program. Till exempel är det en tråd som börjar exekvera i main varje gång du startar ett program. Skillnaden mellan att ha flera trådar i ett program och att ha flera program igång samtidigt är dock väsentlig: operativsystemet ser till att individuella program fungerar, medan du själv får se till att det fungerar när du programmerar för flera trådar inom ett program. Utan att förklara på djupet kan sägas att ett program, som exempelvis chattservern som du snart ska programmera, behöver flera trådar eftersom programmet behöver göra flera saker samtidigt. Chattservern måste dels vänta på klienter som vill ansluta och dels ”lyssna” efter data från varje enskild klient.

62

10 Praktisk programmering – TCP/IP och trådar

Dessutom måste chattservern vänta på inmatad data från serveroperatören. Även klienten måste ha flera trådar: en för att vänta på data från servern och en för att ta emot tangentbordsdata från användaren. För att skapa en tråd så kan du ärva en Java klass Thread. När du anropar metoden start på en instans av Thread så börjar tråden exekvera i metoden run (ungefär som ett program börjar exekvera i main): class MyThread extends Thread { public void run() { System.out.println(”Jag kör i en annan tråd!”); } }; MyThread myThread = new MyThread(); myThread.start();

Analysfas Du får först några basala förutsättningar för chattservern och chattklienten.

Vad ska chattservern göra? I stora drag ska chattservern göra följande: 1. Öppna en socket för att kunna lyssna på anslutande chattklienter. 2. Starta en tråd som väntar på att chattklienter ska ansluta. 3. När en klient ansluter ska chattservern starta en tråd för att lyssna på data som klienten skickar. Klienten ska få ett hälsningsmeddelande direkt vid inloggningen. Alla andra klienter ska få ett meddelande om den nytillkomna klientens närvaro. 4. Vänta på att serveroperatören skriver in någon text.

Vad ska chattklienten göra? 1. Fråga vilket ”nick” användaren vill ha, det vill säga inloggningsnamnet. 2. Fråga vilken server (IP-adress) klienten ska ansluta till. 3. Ansluta till chattservern. Skicka inloggningsdata, som bara är namnet på användaren. 4. Starta en tråd som väntar på data från chattservern. 5. Vänta på att användaren matar in text. 6. Koppla ner.

63

10 Praktisk programmering – TCP/IP och trådar

Designfas Vilka funktioner behöver servern? 1. Öppna socket och knyta den till den lokala IP-adressen. 2. Vänta på anslutningar från klienter. 3. Lägga till en användare när en klient loggar in. 4. Vänta på data från de inloggade klienterna. 5. Skicka ett meddelande till en klient. 6. Skicka ett meddelande till alla inloggade klienter. 7. Ta bort användare när en klient loggar ut. 8. Hantera text som serveroperatören skriver in. 9. Koppla ner.

Vilka funktioner behöver klienten? 1. Öppna socket. 2. Vänta på indata från servern. 3. Ansluta till servern. Skicka användarnamn. 4. Hantera text som användaren matar in. 5. Koppla ner.

Gemensamma funktioner? I normala fall hade man lagt gemensam funktionalitet i en eller flera gemensamma projekt eller en eller flera gemensamma .java-filer, men vi bryr oss inte om det här eftersom det blir så lite kod.

Hantera text? Texten som matas in är ibland ett chattmeddelande och ibland ett kommando. Kommandon i chattklienter (till exempel för IRC) brukar inledas med ett snedstreck.

64

10 Praktisk programmering – TCP/IP och trådar

Hejsan alla! gunnar_gren: Hejsan alla! /bye

Den första raden är inmatningen från ett meddelande (1). Meddelandet skickas till servern. Servern lägger på användarnamn och bildar ett nytt meddelande (2). Meddelandet (2) är det som skrivits ut på rad två. På den sista raden står ett kommando: /bye. Denna typ av kommando är lämpligt att använda för att avsluta.

Vilka kommandon? I detta exempel så kommer du bara att implementera ett enda kommando: /quit – för att avsluta applikationen. Dock kan man lätt tänka sig en hel uppsjö med kommandon. Vissa kommandon bör av säkerhetsskäl bara finnas på servern. Du kan även lägga in synonymer, det vill säga flera kommandon som gör samma sak för att det ska vara lättare att gissa. Några få exempel på kommandon: /disconnect, /connect, /help, /?, /private, /info, /name, /bye, /quit, /exit, /kick-user, /kick-ip, /ban-user, /ban-ip.

Vilken data behöver servern? Detta syftar alltså till medlemsvariablerna. 1. En klass för en användare. 2. En socket för att lyssna efter klientuppkopplingar på.

Vilken data behöver klienten? Med andra ord, vilka medlemsvariabler behöver klienten? 1. En socket för att koppla upp sig mot servern med. 2. En PrintWriter för att skicka text med.

3. En BufferedReader för att läsa text med.

Övrig data Lägg gärna alla strängar som konstanter.

65

10 Praktisk programmering – TCP/IP och trådar

Hur fungerar uppkopplingen och login?

Direkt efter att klienten lyckats med sitt anrop till konstruktorn Socket, det vill säga uppkopplingen gick bra, så ska klienten skicka en sträng med sitt användarnamn i. Så här ser ett tidsschema ut ur serverns perspektiv: Anslutande klient

Server

Redan anslutna klienter

Öppna socket Vänta på att användare ska koppla upp connect() Initiera ett användarobjekt Skicka användarnamn Lägg till namnet i användarobjektet Skicka välkomstmeddelande Skicka information om inloggning Tid

Implementationsfas Det kan tänkas att du vill lägga till fler funktioner än de som är listade ovan för att göra koden bättre och mer överblickbar. Du kommer bara att implementera klienten; den är enklast. Om du vill implementera servern också så får du självfallet det, dock får du ingen annan hjälp än den färdiga källoden till chattservern: SdbChatServer.

Implementera funktioner för chattklienten 1. Skapa ett nytt projekt som du kallar för ChatClient. 2. Namnge och skriv in definitionerna för medlemsvariablerna och prototyperna för metoderna. 3. Sätt ut kommentarer i main som talar om i vilken ordning du ska göra anropen till de olika metoderna. 4. Börja med det du är säker på: skriv färdigt en metod i taget. De enklaste metoderna är de som kopplar upp en socket och skickar användarnamn, respektive den som kopplar ner en socket.

66

10 Praktisk programmering – TCP/IP och trådar

5. Implementera sedan metoden för att hantera användardata. Använd funktionerna Sdb.in.readLine och String.equals för att låta användaren mata in data och för att jämföra strängarna med till exempel kommandot /quit. 6. Implementera sist funktionen för att koppla upp sig och skicka användarnamn. Jämför med tidigare information i kapitlet och försök att på egen hand finna ut hur du ska skriva. 7. Om du kör fast och absolut inte kan komma på hur du ska lösa problemet så kan du alltid tjyvkika på den färdiga chattklienten SdbChatClient. När du är färdig med klienten går du över till testfasen.

Testfas 1. Öppna projektet SdbChatServer. Kompilera och kör. 2. Starta din chattklient. 3. Ange ditt användarnamn. 4. Ange vilken adress servern har som du ska ansluta till. Servern skriver ut nätverksnamn och IP-adress i slutet av andra raden när den startar. Titta på den och skriv av. Fungerade det? Jag hoppas verkligen det! I så fall tycker jag att du ska skicka ut din chattklient till dina klasskompisar tillsammans med din IP-adress och ha sedan chattservern igång så att du kan testa att chatta via din alldeles egna klient! Glöm inte heller att skicka med instruktioner för hur man startar klienten!

67

10 Praktisk programmering – TCP/IP och trådar

Övningsuppgifter Övning 10.1

Verifiera att du förstått allting i kapitlet. Gå igenom det som var svårt några gånger extra.

Övning 10.2

Gör en egen chattserver som är kompatibel med chattklienten i kapitlet.

Övning 10.3

Kan du kombinera dessa kunskaper i TCP/IP med någon annan slags applikation? Kanske ett spel? Eller kanske för att skicka krypterade meddelanden till kompisar? Om du kombinerar nätverksprogrammering med dina nyvunna kunskaper i bildhantering från tidigare kapitel så kan du skapa enkla ritprogram där flera användare kan rita samtidigt på olika datorer. Eller så kan du göra ett program där flera personer kan skapa ett bildkollage tillsammans. Fantasin är det enda som sätter gränsen för vad du kan komma på för applikationer. Gör en valfri applikation som inkluderar TCP/IP. (Svar saknas i facit.)

68

11

Praktisk programmering – läsa andras kod

I detta kapitel Syftet med det här kapitlet är att lära dig läsa och modifiera existerande och mer avancerad kod. Som programmerare i ett projekt med flera deltagare så råkar man betydligt oftare ut för att läsa och modifiera andras kod (eller gammal kod man glömt bort hur den funkar) än att faktiskt skriva egen. Som en bonus handlar det om 3D-rendering i OpenGL, vilket många som nyss börjat med programmering är nyfikna på. OpenGL stöds i många plattformar, om man kan Java kan man även skriva program för Android-enheter, men det är inte heller allt för svårt att gå vidare till C++ och skriva OpenGL-program till både Mac och iPhone/iPad. I kapitlet ges inga förklaringar till OpenGLs funktionalitet – det är bortom målen i kursen. Men det torde inte hindra den entusiastiske från att hitta goda möjligheter för egen innovation.

Överblick När du öppnar en Java-fil som du inte skrivit själv så börja alltid med att skaffa dig en överblick i hela filen. Ett vanligt nybörjarfel är att stirra sig blind på detaljerna så att man har svårt att skaffa sig en helheltsbild. Det är väsentligt att man skaffar sig en helhetsbild av koden man ska ändra i innan man skrider till verket. Annars är risken stor att man missuppfattar övergripande mål med koden man ändrar i. Och om man missförstår syftet bakom en viss algoritm, så är det lätt hänt att man i sina ändringar tillför buggar. Koden du kommer läsa i detta kapitel innehåller vissa syntaktiska (”Java-grammatiska”) formuleringar som du inte tidigare stött på. Som nybörjare är det bara att vänja sig! Eftersom du har som mål att förstå programmet på hög nivå, så måste du försöka att bortse från alla detaljer du inte förstår. Gå in med inställningen att du i varje läge bara ska försöka förstå tillräckligt för komma vidare. Bli inte missmodig om du känner dig ”vilsen”; det gör alla programmerare ibland. Efter bara några minuter kommer du att finna att du har en övergripande uppfattning om programmet, och då vet du bättre var du ska sätta in dina stötar.

69

11 Praktisk programmering – läsa andras kod

Hugg in Kika i katalogen Duck/. Öppna projektet och rota runt lite. Försök bilda dig en övergripande uppfattning om vad det är för ett program. Du väljer själv hur du skaffar dig den uppfattningen; om du tycker det är svårt får du lite vägledning direkt. 1. Testkör. Ingenting är så talande som att provköra en kodsnutt som du ska sätta dig in i. 2. Kolla snabbt igenom samtliga .java-filer. 3. Hitta till konstruktorn. I huvudmetoderna av koden du ska granska hittar du oftast de stora penseldragen i vad den ursprungliga programmeraren tänkt. 4. Om koden du läser är väldigt omfattande så brukar huvudmetoderna innehålla en väldigt hög och abstrakt nivå på anropen. Om mängden kod däremot är liten så kommer du finna högnivåanrop blandat med anrop på en lägre nivå. Eftersom ditt mål är att skaffa dig en överblick så måste du försöka sila bort lågnivåanropen när du läser igenom koden. Kodmängden i det här programmet är att anse som väldigt liten. Du kommer därför se, och förhoppningsvis ignorera, en hel del lågnivåanrop. Till exempel är alla anrop som börjar på gl.gl, lågnivåanrop direkt till OpenGL; dem är det alltså bäst att ignorera tills vidare. 5. Skriv ner pseudokod för programmet i en textredigerare. På så sätt är det enkelt för dig att utöka pseudokoden i takt med att du förstår mer om vad som görs. Din första pseudokodsnutt för programmet Duck bör innehålla ungefär 10–20 rader för huvudfunktionerna i konstruktorn och renderingsmetoden. Nu har du antagligen redan en ganska god bild av vad programmet gör, ungefär hur många rader (relevant) kod som ingår i programmet och ungefärligen hur programmet är uppbyggt med initiering och huvudloop. Nu när du förstår helheten på den här nivån, så är du redo för att tackla lite detaljer runt implementationen. Vissa av uppgifterna i det här kapitlet kan tyckas svåra, eftersom du inte är fullt införstådd med alla detaljer än, men de visar på din förmåga att lösa problem även om du bara känner till koden på en abstrakt nivå. Som programmerare är det oftast mycket viktigare att snabbt ta itu med problemlösning än att på förhand förstå samtliga detaljer kring ett problem.

70

11 Praktisk programmering – läsa andras kod

Övningsuppgifter Övning 11.1

Beskriv kort vad programmet Duck gör.

Övning 11.2

Hur många rader relevant kod anser du ingår i projektet? Motivera.

Övning 11.3

Beskriv huvudfunktionerna i konstruktorn och metoden render med pseudokod på en övergripande nivå.

Övning 11.4

Tror du att 3D-modellen som visas i programmet rör sig med samma hastighet på en snabb och en långsam dator? Motivera.

Övning 11.5

3D-modellen ritas ut som trianglar. Hur många trianglar består den av? Hur räknar man ut det, och i vilken fil ska man titta?

Övning 11.6

Hur modifierar du programmet så att både modellen och bakgrunden rör sig tio gånger snabbare?



Återställ programmet i sin ursprungliga hastighet när du är klar.

Övning 11.7

Modifiera programmet så att endast bakgrunden (inte modellen) rör sig tio gånger snabbare.

Övning 11.8

Hitta var bakgrundsfärgerna sätts. Vilken funktion är det som sätter dem?

Övning 11.9

När du tittar i funktionen i 11.8 så ser du i vilken ordning hörnpunkterna beskrivs för OpenGL. I vilken ordning vill OpenGL ha en hörnpunkt – först färg, sedan position eller först position, sedan färg?

Övning 11.10

Kika vidare i funktionen i 11.8. I den funktionen ritas bakgrunden ut som en rektangel. Det är vad gl.glBegin(GL.GL_QUADS); betyder. I vilken ordning sätts positionerna på de fyra hörnpunkterna på bakgrundsrektangeln ut?

71

11 Praktisk programmering – läsa andras kod

Övning 11.11

Vi kollar ytterligare i funktionen från 11.8. De funktioner som anropas för att ställa in bakgrundsfärgerna anger RGB (rött, grönt, blått) i intervallet [0, 1] där 0 och mindre betyder ingen färg och 1 och högre betyder maximal färgstyrka. Du är van med RGB sedan tidigare, skillnaden här är att intervallet beskrivs av ett flyttal mellan 0 och 1 i stället för ett heltal mellan 0 och 255.



Du kan se i koden att färgernas värden sätts med hjälp av trigonometriska funktioner.



Ändra så att alla färgerna ritas ut i gråskala, fast med samma intensitet som respektive trigonometrisk funktion ger. I den andra hörnpunkten (som har två anrop till trigonometriska funktioner) väljer du den intensiteten som den första trigonometriska funktionen returnerar.



Hur ser den resulterande koden mellan gl.glBegin och gl.glEnd ut?

Övning 11.12

Börja med att kommentera bort anropen från metoden render till DrawWireFrame.



Programmet är redan förberett för att få ankan att simma som fisken i vattnet, men det är inte färdigställt än. Kan du komma på hur du får ankan att simma som en ål?



Ledtråd: den ena parametern heter wobble och reglerar hur ”sladdrig” ankan ska vara. Ett lagom värde för en riktigt sladdrig anka är 0.5. Den andra parametern heter angle och gör sig bäst om man matar den med ett värde som successivt ökar typ fem gånger så snabbt som rotationsvinkeln som räknas ut varje loop.

72

12

Nyckelord i Java

Standardiserade nyckelord abstract

goto

this

assert

if

throw

boolean

implements

throws

break

import

transient

byte

instanceof

true

case

int

try

catch

interface

void

char

long

volatile

class

native

while

const

new

continue

null

default

package

do

private

double

protected

else

public

enum

return

extends

short

false

static

final

strictfp

finally

super

float

switch

for

synchronized

73

12 Nyckelord i Java

De vanligaste nyckelorden Här hittar du de vanligaste nyckelorden i Java. För varje nyckelord finns beskrivning, syntax och exempel. A Nyckelord

abstract

Beskrivning

Används på klasser eller metoder för att ange att en implementation ska ligga i en ärvd klass.

Syntax

abstract deklaration

Exempel

abstract class MyClass { abstract void myMethod(); }

B Nyckelord

bool

Beskrivning

Variabeltyp som kan anta två värden: sant och falskt.

Syntax

bool deklaration;

Exempel

bool is_active = false;

Nyckelord

break

Beskrivning

Bryter den innersta loopen.

Syntax

break;

Exempel

while (true) { break; }

C Nyckelord

case

Beskrivning

Ett av flera möjliga utfall i en switch-sats. Måste alltid följas av ett konstant heltal och ett kolon.

Syntax

case konstant_heltal:

74

12 Nyckelord i Java

Exempel

switch (x) { case 3: System.out.print(”Tre!”); break; }

Nyckelord

catch

Beskrivning

Fångar ett undantag.

Syntax

catch (undantag) {}

Exempel

try { ... } catch (Exception ex) { ex.printStackTrace(); }

Nyckelord

char

Beskrivning

Variabeltyp för tecken.

Syntax

char deklaration;

Exempel

char ch = '#';

Nyckelord

class

Beskrivning

Definierar en klass.

Syntax

class Deklaration {}

Exempel

class MyClass { }

Nyckelord

continue

Beskrivning

Fortsätter med nästa steg i en loop.

Syntax

continue;

Exempel

while (true) { continue; }

75

12 Nyckelord i Java

D Nyckelord

default

Beskrivning

Nyckelordet default används endast i switch-satser. Exekveringen kommer till default-alternativet om inget case-alternativ matchar.

Syntax

default:

Exempel

switch (x) { case 0: System.out.print(”Noll”); break; case 1: System.out.print(”Ett!”); break; default: System.out.print(”Fel”); break; }

Nyckelord

do

Beskrivning

Loop som testar villkoret på sista raden. Det innebär att loopen alltid kommer att köras minst en gång. Loopen kommer att exekveras till dess att villkoret är falskt.

Syntax

do { } while (villkor);

Exempel

do { } while (true);

Nyckelord

double

Beskrivning

Variabeltyp för flyttal. 15 signifikanta siffor.

Syntax

double deklaration;

Exempel

double d = 3.1415;

E Nyckelord

else

Beskrivning

Används enbart efter en if-sats. Exekveringen kommer till elsesatsen om inte villkoret i if-satsen är sant.

Syntax

if (villkor) { } else { }

76

12 Nyckelord i Java

Exempel

int x = ...; if (x == 1) { System.out.println(”Ett!”); } else { System.out.println(”Inte ett!”); }

F Nyckelord

false

Beskrivning

false är det ena av de två värdena som variabeltypen bool kan anta. true är det andra.

Syntax

false

Exempel

bool b = false;

Nyckelord

final

Beskrivning

final anger att en klass, metod eller variabel inte kan ändras. En klass kan inte ärvas, en metod kan inte överlagras, en variabel kan inte tilldelas mer än en gång. Variabler kan även användas i nästlade, anonyma klasser.

Syntax

final deklaration

Exempel

final class MyClass { final int x = 7; final void myMethod() { } }

Nyckelord

finally

Beskrivning

finally används tillsammans med try för att hantera oväntade händelser som till exempel när en metod avslutas under en pågående initiering av resurser.

Syntax

finally {}

Exempel

try { ... } catch (Exception ex) { } finally { // Denna kod kommer tt köras, oavsett // vad som händer ovan. }

77

12 Nyckelord i Java

Nyckelord

float

Beskrivning

Variabeltyp för flyttal. 7 signifikanta siffor.

Syntax

float deklaration;

Exempel

float f = 3.1415f;

Nyckelord

for

Beskrivning

En villkorlig loop. Loopen kommer att exekveras till dess att villkoret är falskt.

Syntax

for (uttryck; villkor; uttryck) { }

Exempel

for (int x = 0; x < 3; ++x) { System.out.println(x); }

I Nyckelord

if

Beskrivning

Exekverar villkorliga satser. Innehållet i if-satsen kommer att exekveras om villkoret är sant. if-satsen kan kombineras med en else-sats.

Syntax

if (villkor) { satser; }

Exempel

int x = ...; if (x == 3) { System.out.println(x); }

Nyckelord

implements

Beskrivning

Följs av interface som en klassen implementerar.

Syntax

implents interface

Exempel

class MyClass implements MyInterface { }

78

12 Nyckelord i Java

Nyckelord

import

Beskrivning

Importerar en klass, alla klasser i ett paket eller en statiska medlemmar i en klass.

Syntax

import KlassEllerPaket; static import statiskMetod;

Exempel

import import static static

Nyckelord

int

Beskrivning

Variabeltyp för heltal.

Syntax

int deklaration;

Exempel

int i = -385;

Nyckelord

interface

Beskrivning

Definierar ett interface, en uppsättning odefinierade metoder.

Syntax

interface Deklaration {}

Exempel

public interface MyInterface { void myMethod(); }

java.awt.*; sdb.Sdb; import sdb.Sdb.createConsole; import Math.*;

L Nyckelord

long

Beskrivning

Variabeltyp för heltal.

Syntax

int deklaration;

Exempel

int l = -287;

79

12 Nyckelord i Java

M Nyckelord

main

Beskrivning

Inget nyckelord, men bör inte användas till andra deklarationer än huvudfunktionen.

Syntax

main

Exempel

public static void main(String[] argv) {}

N Nyckelord

new

Beskrivning

Allokerar en ny instans av en klass eller en ny array.

Syntax

new deklaration;

Exempel

new MyClass(); new int[128];

Nyckelord

null

Beskrivning

En referens är null när den inte refererar någon instans.

Syntax

null;

Exempel

String s = null;

P Nyckelord

package

Beskrivning

Talar om vilket paket man är i, högst uppe i källkodsfilen.

Syntax

package deklaration;

Exempel

package game;

Nyckelord

private

Beskrivning

Anger att en klass, en metod eller en variabel bara är tillgänglig från alla den klasssen den definieras i.

80

12 Nyckelord i Java

Syntax

private deklaration

Exempel

private int x;

Nyckelord

protected

Beskrivning

Anger att en klass, en metod eller en variabel är tillgänglig från andra klassser som ärver eller som ligger i samma paket. Om inget anges blir det automatiskt protected i klasser.

Syntax

protected deklaration

Exempel

protected class MyClass { protected void myMethod(); }

Nyckelord

public

Beskrivning

Anger att en klass, en metod eller en variabel är tillgänglig från alla andra klassser. Om inget anges blir det automatiskt public i interface.

Syntax

public deklaration

Exempel

public class MyClass { public void myMethod(); }

R Nyckelord

return

Beskrivning

Returnerar från en metod. Om metoden ska returnera ett värde så ska return ta värdet som parameter. Om det är en void-funktion så ska return inte ta någon parameter

Syntax

return ;

Exempel

void x() { return; } int y() { return 4; }

81

12 Nyckelord i Java

S Nyckelord

short

Beskrivning

Variabeltyp för heltal.

Syntax

short deklaration;

Exempel

short i = -292;

Nyckelord

static

Beskrivning

Gör en metod, medlemsvariabel eller inre klass frikopplad från instansen.

Syntax

static deklaration

Exempel

class Abc { static String def = ”GHI”; static void jkl() {} } System.out.println(Abc.def); Abc.jkl();

Nyckelord

switch

Beskrivning

Villkorlig exekvering av olika satser beroende på heltalsuttrycket. Används tillsammans med nyckelorden case default.

Syntax

switch (heltalsuttryck) { case x: ... case y: ... case z: ... default: ... }

Exempel

int x = ...; switch (x) { case 10: case 91: case 99: default: }

System.out.print(”tio”); System.out.print(”nittioett”); System.out.print(”nittionio”); System.out.print(”annat tal”);

82

12 Nyckelord i Java

T Nyckelord

this

Beskrivning

this refererar till instansen i nuvarande klass.

Syntax

this

Exempel

class MyClass { int x; MyClass() { this.x = 7 } }

Nyckelord

true

Beskrivning

true är det ena av de två värdena som variabeltypen bool kan anta. false är det andra.

Syntax

true

Exempel

bool b = true;

Nyckelord

try

Beskrivning

Kontrollerar ett block där ett eller flera undantag kan ske.

Syntax

try {} catch (undantag) {}

Exempel

try { new File(”.”).canonicalPath(); } catch (Exception ex) { }

U Nyckelord

unsigned

Beskrivning

Anger att en heltalsvariabel enbart ska kunna anta positivia värden.

Syntax

unsigned heltalsdeklaration;

Exempel

unsigned char x = 3;

83

12 Nyckelord i Java

V Nyckelord

void

Beskrivning

void anger att en metod inte ska returnera något värde.

Syntax

void metoddeklaration

Exempel

void setPixel(int x, int y) { }

W Nyckelord

while

Beskrivning

En villkorlig loop. Loopen kommer att exekveras till dess att villkoret är falskt.

Syntax

while (villkor) { }

Exempel

int x = 0; while (x < 3) { System.out.println(x); ++x; }

84

13

Teckentabell

Tecken

ASCII-värde

Namnkod

Funktion

\0

0

NUL

Slut på sträng

\x1

1

SOH

\x2

2

STX

\x3

3

ETX

\x4

4

EOT

\x5

5

ENQ

\x6

6

ACK

\a

7

BEL

Avger en ton

\b

8

BS

Backsteg

\t

9

HT

Tabb

\n

10

LF

Radmatning

\v

11

VT

Vertikal tabb

\f

12

FF

Sidmatning

\r

13

CR

Vagnretur

\xE

14

SO

\xF

15

SI

\x10

16

DLE

\x11

17

DC1

\x12

18

DC2

\x13

19

DC3

\x14

20

DC4

\x15

21

NAK

\x16

22

SYN

\x17

23

ETB

\x18

24

CAN

\x19

25

EM

\x1A

26

SUB

85

13 Teckentabell

Tecken

ASCII-värde

Namnkod

\x1B

27

ESC

\x1C

28

FS

\x1D

29

GS

\x1E

30

RS

\1F

31

US

32

SP

!

33

"

34

#

35

$

36

%

37

&

38

'

39

(

40

)

41

*

42

+

43

,

44

-

45

.

46

/

47

0

48

1

49

2

50

3

51

4

52

5

53

6

54

7

55

Funktion

Mellanslag

86

13 Teckentabell

Tecken

ASCII-värde

8

56

9

57

:

58

;

59




62

?

63

@

64

A

65

B

66

C

67

D

68

E

69

F

70

G

71

H

72

I

73

J

74

K

75

L

76

M

77

N

78

O

79

P

80

Q

81

R

82

S

83

T

84

Namnkod

Funktion

87

13 Teckentabell

Tecken

ASCII-värde

U

85

V

86

W

87

X

88

Y

89

Z

90

[

91

\

92

]

93

^

94

_

95

`

96

a

97

b

98

c

99

d

100

e

101

f

102

g

103

h

104

i

105

j

106

k

107

l

108

m

109

n

110

o

111

p

112

q

113

Namnkod

Funktion

88

13 Teckentabell

Tecken

ASCII-värde

r

114

s

115

t

116

u

117

v

118

w

119

x

120

y

121

z

122

{

123

|

124

}

125

~

126

\x7F

127

Namnkod

Funktion

DEL

89

13 Teckentabell

90

14

Facit

1.1 Java-VM:en exekverar bytekod (1:or och 0:or), instruktion för instruktion. Instruktionerna läses in och utföres ”uppifrån och ner” (det vill säga från lägre till högre adresser), dock finns det instruktioner som kan få Java-VM:en att ”hoppa” till en annan adress för att fortsätta programexekveringen där.

1.2 Man trycker Ctrl+Shift+I!

1.3 En loop är en konstruktion som gör att man kan genomföra samma bearbetning flera gånger utan att behöva skriva källkoden flera gånger. Ofta använder man en loop för att bearbeta olika data i, men med en och samma funktion. Till exempel skulle en loop lämpa sig idealiskt för att söka igenom telefonkatalogen: varje dataelement har ju samma format (namn och telefonnummer), men data skiljer sig åt (alla har inte samma namn eller telefonnummer).

1.4 .java. Filer med ändelsen .java innehåller programkoden som ska översättas till bytekod.

1.5

byte, short, int, long, float, double, bool, char, enum.

De fyra första typerna är heltal. De två nästkommande är flyttal. Näst kommer en så kallad boolesk variabel som endast kan anta värdena true och false. char används för tecken. Typen enum är till för uppräkningar, men kan även användas ungefär som en klass.

1.6

short x;

1.7

+, –, *, / och %. Dessutom +=, –=, *=, /=, %=, ++ och ––. Det finns även fler operatorer, men de har du inte gått igenom än. Några av dessa används för binär aritmetik. De är: >>, midValue; ++top) ; for (; stars[bottom].z < midValue; --bottom) ; if (top first) { sortStars(stars, first, bottom); sortStars(stars, top, last); } }

6.1 –

6.2

System.arrayCopy (används för att kopiera arrayer), String.equals och String.valueOf, PrintWriter.println och så vidare.

7.1 Se exempelprojektet SdbSearchPerformanceTest.

97

14 Facit

7.2

SearchPerformanceTest() { int nameCount = 30; // Nollställ hashtabellen och listan. testHashTable = new ListItem[256]; for (int a = 0; a < 256; ++a) { testHashTable[a] = null; } testList = null; // Lägg in data. for (int i = 0; i < nameCount; ++i) { hashAddNode(testHashTable, Names.names[i][0], Names.names[i][1]); testList = listAddNode(testList, Names.names[i][0], Names.names[i][1]); } // Sök efter data i hashtabellen. long Time1 = System.nanoTime(); for (int i = 0; i < nameCount; ++i) { hashAddNode(testHashTable, Names.names[i][0], Names.names[i][1]); } for (int i = 0; i < nameCount; ++i) { hashFindNode(testHashTable, Names.names[i][0], Names.names[i][1]); } long Time2 = System.nanoTime(); System.out.println(”Hash time: ” + (Time2-Time1)); // Sök efter long Time3 = for (int i = testList =

}

data i listan. System.nanoTime(); 0; i < nameCount; ++i) { listAddNode(testList, Names.names[i][0], Names.names[i][1]);

} for (int i = 0; i < nameCount; ++i) { listFindNode(testList, Names.names[i][0], Names.names[i][1]); } long Time4 = System.nanoTime(); System.out.println(”List time: ” + (Time4-Time3));

Resultatet för få namn (= b.height) { y2 = b.height-1; } int i = imageOffset + 3*x + 3*(b.width)*(b.height-1-y2);

Resultatet blir en något svängigare bild.

99

14 Facit

9.1

List list = new ArrayList();

9.2

HashMap numberLookup = new HashMap(); numberLookup.put(31, ”Göteborg”); numberLookup.put(8, ”Stockholm”); numberLookup.put(40, ”Malmö”);

10.1 –

10.2 Se källkoden i SdbChatServer.

10.3 –

11.1 Programmet ritar ut en roterande anka. I bakgrunden varierar en färggradient; varje hörn på skärmen har en egen pulserande nyans av rött, grönt, gult, blått och svart.

100

14 Facit

11.2 Ungefär 200 rader. Det är egentligen bara filerna Duck.java, Render.java som innehåller algoritmer som vi är intresserade av att titta på och ändra i. Filen DuckMesh.java innehåller bara data – nämligen hörnpunkter och trianglar för ankan. Den behöver vi bara kolla på en gång för att inse att den inte innehåller några algoritmer, och helt ointressant för manuell redigering. Filen SdbGl.java innehåller bara sådant som vi varken vill eller behöver tänka på (öppna fönster, sköta basala inställningar, och så vidare).

11.3

Öppna ett OpenGL-fönster. Räkna ut normalerna till hörnpunkterna på modellen. Lagra start-tiden. [HuvudLoop] vinkel = tid (i sekunder) sedan start Alla dessa är beroende av vinkel med skalfaktor: Rita bakgrunden. Rotera modell och ljuskälla. Rita modellen med fyllda trianglar. Rita modellen med ofyllda trianglar. Gå till [HuvudLoop]!

11.4 Ja. Orsaken är att den absoluta ”vinkel” som används för bakgrunden och modellen är tidbaserad (sekunder sedan programmet startade) och inte baserad på något annat, tidigare tillstånd. Tiden går lika fort för alla datorer, oavsett hur snabba de är.

11.5 Filen DuckMesh.java innehåller vad vi vill veta. Den första arrayen, DuckMesh.vertices, listar hörnpunkterna i trianglarna på ankan. Den andra arrayen, triangles, listar trianglarna som ankan består av. En triangel definieras som index på de tre ingående hörnpunkterna. Antalet definierade rader i DuckMesh.triangles är lika med antalet trianglar. Det antalet är 564.

101

14 Facit

11.6 Ändra raden float angle = elapsedTime;

till

float angle = elapsedTime * 10;

11.7 Ändra raden Render.drawBackground(angle / 25);

till

Render.drawBackground(angle * 10 / 25);

11.8

De anges i funktionen Render.drawBackground.

11.9 Först färg, sedan position. (Positionen anges sist för varje hörnpunkt i OpenGL.)

11.10 Hörnpunkterna sätts ut i följande ordning: övre vänstra, nedre vänstra, nedre högra, övre högra. Moturs, således.

11.11

gl.glBegin(GL.GL_QUADS); double d = Math.sin(a * 2); gl.glColor3d(d, d, d); gl.glVertex2d(-1.0, 1.0); d = Math.cos(a * 3); gl.glColor3d(d, d, d); gl.glVertex2d(-1.0, -1.0); d = Math.sin(a * 7) * Math.cos(a); gl.glColor3d(d, d, d); gl.glVertex2d(1.0, -1.0); d = Math.sin(a * 11 + 1); gl.glColor3d(d, d, d); gl.glVertex2d(1.0, 1.0); gl.glEnd();

102

14 Facit

11.12 Ändra anropet Render.drawMesh(DuckMesh.vertices, duckMeshNormals, DuckMesh.triangles, 0, 0);

till

Render.drawMesh(DuckMesh.vertices, duckMeshNormals, DuckMesh.triangles, 0.5f, angle * 5);

De två sista parametrarna är valfria; det kan du se på funktionsprototypen.

103