732G14 Programmering 2 HT 2008 Inledning Denna kurs består av tre föreläsningar och en laborationskurs. Laborationskursen utgör hela examinationen av kursen och består av två laborationer. Den första laborationen är avsedd att kort repetera det du lärt dig i tidigare programmeringskurser, och sedan öva på nya begrepp som införs under föreläsningarna. Denna laboration är därför lämplig att påbörja innan första föreläsningen. Den andra laborationen är ett litet projekt där du får tillämpa dina kunskaper på ett verkligt statistikrelaterat problem. Komma igång med Eclipse Eclipse är ett utvecklingsverktyg som nns tillgängligt gratis för de esta olika operativsystemen. En av nackdelarna med eclipse är att det har ganska många funktioner, och kan därför vara lite förvirrande i början. Här nns därför en steg-för-steg guide till hur man skapar sitt första projekt i Eclipse. För dig som känner att du behärskar grunderna nns avsnitt, där introduceras några mycket användbara men inte nödvändiga tips. Starta eclipse 1. Starta Eclipse, om du sitter vid en Windows-maskin välj Program → Eclipse → Eclipse 2.4.2. Start → Sitter du vid en sun-maskin så måste du öppna en terminal, Högerklicka på skrivbordsytan och välj Terminal. Kör följande kommandon: module add module initadd prog / e c l i p s e prog / e c l i p s e eclipse Vänta tålmodigt, det tar ett tag att starta Eclipse. 2. Om detta är första gången du öppnar Eclipse så får du välja var din workspace ska ligga. Workspace är helt enkelt var Eclipse ska spara dina projekt. Vi föreslår att du använder standardmappen. 3. Om du får en skärmbild med ett antal bilder på så ska du klicka på den böjda pilen. Skapa ett projekt 1. Skapa ett nytt projekt. Detta gör du genom att högerklicka i den Package Explorer efter välja New → Java Project. vänstra panelen 2 eller i menyn välja File och där- 2. Du borde nu ha fått upp ett fönster som heter New Java Project. Ange ett bra projektnamn, detta kommer även att bli namnet på den underkatalog i din workspace där projektet lagras och det namn som visas i Package Explorer. Vi föreslår att du döper projekten efter övningsnamnen (Repetition, Objektorientering och så vidare). 3. Du kan även ange lite andra inställningar, men lämna dessa som de är tills vidare. 4. Tryck Finish för att skapa ditt projekt. Skapa en klass 1. Högerklicka på projektnamnet i i välj Package Explorer till vänster och New → Class. Strunta i de tre översta fälten. Skriv ditt klass- namn på fjärde raden (klassnamn skrivs med inledande versal). 2. Kryssa sedan eventuellt i att du vill generera public static void main (String[] args). Detta kommer att göra klassen du skapar körbar. Du vill normalt ha en sådan klass per projekt, men du kan ha er om du vill. 3. Klicka Finish, och du har skapat en klass. Kör en klass 1. I verktygsraden, klicka på den lilla svarta nedåtriktade pilen till höger om den stora gröna cirkeln med en vit play-symbol i. Välj Run Congurations. 2. Dubbelklicka på rätt typ av applikation, detta är normalt sett Java Application. Listan uppdateras nu och du borde se alla klasser som matchar den valda applikationstypen. Markera den klass du vill köra. och klicka på Run. Laboration 1, Introduktion till Java Denna del innehåller en snabb repetition av den tidigare programmeringskursen. Om du känner att du redan behärskar det som behandlas så är det bara att hoppa över de delarna. Hello world Denna klassiska uppgift är till för att du ska komma igång med utvecklingsverktyget eclipse. Du får även bekanta dig med utmatning av text till terminalfönstret. 3 Uppgift 2 Skapa ett nytt projekt, ett lämpligt namn är Repetition. Skapa en klass som du kallar för HelloWorld, denna klass skall vara körbar. Ändra i klassen HelloWorld så att den ser ut som i kodexempel 1. Kör nu din klass. 1 public class HelloWorld { 2 3 public static void main ( String [] args ) { 4 System . out . println (" Hello world " ); 5 } 6 7 } Kodexempel 1: HelloWorld.java När du kör din klass ifrån eclipse så kommer den text som normalt skulle ha skrivits till terminalfönstret att skrivas till iken som heter Console, den ligger i nederdelen av Eclipse-fönstret. I det här fallet rör det sig alltså om texten Hello World som borde ha skrivits ut. Indata För inläsning av data kan man använda sig av showInputDialog() för att få en dialogruta. Denna funktion beskrivs i kapitel 1.12 i Skansholm. Uppgift 3 Eftersom det är lite tråkigt med program som gör samma sak varje gång de körs så ska du nu ändra i Hello world så att det frågar efter användarens namn och sedan säger Hej Peter (om du nu heter Peter). Villkor och reguljära uttryck Villkorssatser, eller if-satser, används för att avgöra vad som ska hända i ett program baserat på något godtyckligt villkor. För att enkelt jämföra strängar nns i java något som kallas reguljära uttryck. If-satser behandlas i kapitel 1.10 i Skansholm. För mer information om reguljära uttryck, se http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html. Uppgift 4 Se till att Hello world programmet hälsar lite extra hövligt på folk som 4 har just ditt underbara namn. Både personer med samma förnamn och personer med samma efternamn. Använd reguljära uttryck. Arrayer och loopar Arrayer, eller fält som man ibland säger på svenska, är ett antal objekt av samma typ. De behandlas närmare i kapitel 9.3 i Skansholm. De olika repetitionssatserna nns i kapitel 1.12 och frammåt. En lämplig funktion för att göra utskrifterna är format, och beskrivs i kapitel 5.3. Uppgift 5 Lägg till en array av heltal i din HelloWorld klass. Skriv sedan ut den, snyggt formaterad med hjälp av två loopar. Entalssirorna ska vara justerade ovanför varandra i de olika raderna. Du får anta att alla talen i arrayen innehåller högst tre siror. Nedan nns ett förslag på hur utskriften kan se ut. 1 123 13 23 3 1 14 14 5 Eclipse-tips Här bjuds på kraftfulla men enkla Eclipse-tips som alla rekomenderas läsa och som kommer att spara tid för de esta, men som inte behövs för att klara kursen. Öppna/stänga ett projekt Detta är speciellt användbart om du har fel/varningar från era projekt. Inga fel/varningar visas nämligen från stängda projekt. Högerklicka på projektnamnet i i Open Project Project Explorer till vänster och välj eller emphClose Project. Visa utskriftsmarginal Window → Preferences → General → Editors → Text-editors → Show Print Margin I huvudmenyn, välj Kör senaste konguration Detta kommandot kör den senast körda javalen, det verkar dock inte fungera på SUN-maskinerna. Tryck Ctrl + F11 5 Kommentera / avkommentera rad Markera den text du vill kommentera eller avkommentera. Observera att om du väljer era rader och vissa inte är kommenterade så kommer verktyget att kommentera alla raderna igen. Tryck Ctrl + 7 Automatisk indentering Markera den text du vill indentera och tryck Ctrl + i Få kodförslag Som de esta andra utvecklingsmiljöer kan även Eclipse ge kodförslag. Skriv något och tryck Ctrl + Space. Eclipse har också ett antal förde- nierade genvägar som är väldigt användbara, i många fall fyller Eclipse själv i delar av exempelvis loop-konstruktionerna utifrån den omgivande koden. genväg syso if for foreach resultat System.out.println(); if (condition) { } for (int i = 0; i < array.length; i++) { } for (type element : iterable) { } Quick x Om du har ett fel i din kod så kan Eclipse föreslå en lösning. Klicka där felet nns och tryck Ctrl + 1 (etta). Eclipse föreslår då vad du kan göra för att lösa problemet. Observera dock att detta inte ersätter hjärnaktivitet, du måste fortfarande veta vad du vill göra, Eclipse gör bara vägen dit lite kortare. Generera åtkomstmetoder Eclpse kan autogenerera get-/setmetoder. Markera de instansvariabler du vill generera för, Högerklicka i koden och välj Getters and Setters. . . Ob jektorientering Objektorientering beskrivs i kapitel 2 i Skansholm. 6 Source → Generate Wrapper Klassen Wrapper är en mycket enkel klass son bara har en enda uppgift, att innehålla ett heltal. Trots att detta är en mycket simpel klass så illustrerar den många bra programmeringsvanor. Mer om Wrapper klasser kan ni hitta i Skansholm, kapitel 3.7. 1 public class Wrapper { 2 3 private int value ; 4 5 public Wrapper (){ 6 value = 0; 7 } 8 9 public int getValue (){ 10 return value ; 11 } 12 13 public void setValue ( int value ){ 14 this . value = value ; 15 } 16 17 } Kodexempel 2: Wrapper.java Datagömning och inkapsling Heltalet value är deklarerat som en privat instansvariabel, vilket betyder att den bara kan användas innuti klassen där den deklarerats. Så varför är detta bra? Jo, i och med att man separerar implementationen (hur man gör något) från gränssnittet (hur man använder något) så bibehåller man möjligheten att ändra implementationen utan att påverka gränssnittet. Man skulle till exempel kunna välja att lagra värde utifrån hur mycket större än 10 det är (varför i hela världen man nu skulle vilja det). Du skulle då tvingas ändra i getValue och setValue, men de som använder din klass skulle inte märka något. Man skulle också kunna lagra värdet som en annan datatyp, till exempel få ändra lite i getValue. double, även här kommer man att Kapitel 3.2 i Skansholm handlar om datagömning Uppgift 6 Prova att utföra ändringarna ovan (lagra datatyp för value) 7 value − 10, samt att byta Konstruktor Wrapper är inte riktigt som alla andra funktioner, exempelvis saknar den en returtyp. Wrapper är en konstruktor, och har därför exakt Funktionen samma namn som klassen i fråga. En konstruktor får inte ha någon returtyp och körs automatiskt när man skapar en ny instans av en klass. Det kan nnas era överlagrade konstruktorer som då måste ha olika pa- rameterlistor, eller signaturer som man brukar säga. Alla konstruktorer i en klass har dock samma namn. Skansholm kapitel 2.10 handlar om konstruktorer och 2.11 handlar om överlagring. Uppgift 7 Skapa en ny konstruktor där man får ange vilket heltal Wrapper ska innehålla när man skapar det. Behåll den gamla konstruktorn. Referenser Alla objekt i java är referenser, medan alla inbyggda typer (exempelvis int) inte är det. Detta betyder att man måste tänka lite extra ibland. Exempel på tillfållen när man ska vara extra noga är vid tilldelning och vid jämförelse. Kapitel 2.5 och 2.6 i Skansholm handlar om referenser respektive tilldelningar. Uppgift 8 Skapa en ny körbar klass. Den ska innehålla två int och två Wrapper. Ge dem bra namn så att man kan skilja dem åt. Du ska initiera ett av heltalen och ett av Wrapper-objekten till 3, övriga ska vara oinitierade. Tilldela nu heltal två värdet av heltal ett och motsvarande för Wrapper-objekten. Använd =-operatorn. Vad innehåller de olika variablerna? Wrapper-objekt ett till 0. Använd setValue() för Wrapper-objektet. Vad Ändra nu värdet på heltal och =-operatorn för heltalet och innehåler variablerna nu? Varför? Generiska klasser Klassen wrapper är ju uppenbarligen inte så enormt exibel. Den innehåller ett heltal. Vill man ha en Wrapper för andra objekttyper så får man vackert skapa en ny klass. Det måste dock inte vara så. Man kan nämligen göra en klass generisk eller parametriserad . Det betyder att man för vissa variabler inte förutbestämmer någon typ, utan anger den som en parameter när man instantierar klassen. 8 Kapitel 17.11 i Skansholm handlar om generiska klasser. Uppgift 9 Wrapper parametriserad. Kom ihåg att du måste ändra typ för value såväl som för din nya konstruktor och get-/setfunktionerna. Gör Arv En klass kan ärva egenskaper från en annan. Objekt av den nya klassen kommer att kunna behandlas som om den vore en instans av den gamla, men kan ha nya metoder och variabler. Den nya klassen kan alltså ha funktionalitet som den gamla saknade. Man brukar säga att den nya klassen är mer specialicerad än den gamla. Kapitel 10 i Skansholm handlar om arv. Uppgift 10 PrintableWrapper till Wrapper. Subklassen ska ha en funktion som heter print() och skriver ut innehållet på något Skapa en subklass vackert sätt. Listan I denna laboration ska du få skapa en lite mer avancerad datatyp, listan. En lista består av 0n noder och varje nod innehåller ett heltal. Varje nod i listan har referenser till noden före och efter, listan är en så kallad dubbellänkad lista. Man kan lägga till saker i listan och man kan ta bort saker, men bara med hjälp av en iterator. Iteratorn är en hjälpklass som har går igenom noderna en efter en och kommer ihåg vilken nod den är på under tiden. Klassen NiceList Den här listklassen ska använda sig av något som kallas för sentinel. Principen är att man istället för att göra en rak lista, gör en cirkulär. NiceList ska innehålla en referens till en Node som alltså är vår så kallade sentinel. Denna nod ska alltid existera och skapas således i konstruktorn. Till att börja med så pekar dess före- och efterreferenser på sig själv. Man ska kunna lägga till ett nytt tal i listan. en funktion som heter NiceNode-objekt add(int value). NiceList behöver därför Funktionen ska skapa ett nytt som innehåller det aktuella värdet, och sätta denna noden sist i listan genom att göra följande. 1. sätt den nya nodens förra objekt till sentinelens förra 9 2. sätt nya nodens förras nästa till den nya noden 3. sätt nya nodens nästa till sentinelen 4. sätt sentinelens förra till den nya noden Klassen lista ska implementera gränssnittet funktion som heter iterator() som returnerar Iterable. Lägg till en ett nytt NiceIterator- objekt för den aktuella listan. Klassen NiceNode Detta är en intern klass i NiceList. Den innehåller referenser till två andra noder (noden före och efter). Dessa noder bör vara privata, och använda get/set metoder. I övrigt fungerar den precis som den ursprungliga Wrapper klassen. Klassen NiceIterator Detta är en intern klass i NiceList, den implementerar interfacet Iterator<int> och innehåller tre funktioner. Men till att börja med så måste den ha en referens till en nuvarande NiceNode för att kunna hålla reda på var i listan den benner sig. Låt noden börja referera till listans sentinel. Funktionen boolean hasNext() talar om ifall det nns er noder i listan. Detta är ekvivalent med att nuvarande nods nästa inte är sentinel. Funktionen int next() returnerar nästa värde i listan, eller ger fel om inget nästa värde nns. Nuvarande ska självfallet uppdateras så att den pekar rätt. void delete() tar bort det senast returnerade värdet. sådant värde nns (next() har aldrig körts eller om värdet Funktionen Om inget redan har tagits bort) så ska ett fel skapas. 1. om nuvarande är sentinel eller om nuvarandes föregående är null, ge fel 2. sätt nuvarandes föregåendes nästa till nuvarandes nästa 3. sätt nuvarandes nästas föregående till nuvarandes föregående 4. sätt nuvarandes föregående till null Uppgift 11 Skapa klasserna enligt specikationen ovan. Se därefter till att allting fungerar. 10