7 Mest om metoder… Javas klassbibliotek Allmänt om metoder Metoderna i klassen Math Trigonometriska övningar Experiment med slumptal Förvandla sträng till decimaltal Antal decimaler i utskrift Metoder i en applet Metoder som returnerar värde Egna klassmetoder Kap 7: Sid 2 Här återkommer vi till Javas klassbibliotek, och du får lära dig hur man söker i den dokumentation som bifogas JDK/SDK. Viktigt! Efter detta följer en repetition av de begrepp som förekommer i samband med metoder (du har tidigare mött begreppen i kapitel 2). Passa på att repetera! Därefter presenteras klassen Math. Klassens metoder för matematiska beräkningar exemplifieras i flera övningar. Vidare lär du dig metoder för att utföra avrundning av tal. Användbart! I ett avsnitt behandlas (återigen) de speciella metoder som ingår i en applet. Här lär du dig en teknik för att rita om en applet samtidigt som den gamla bilden ligger kvar. Vissa metoder returnerar värde (funktioner). Dessa exemplifieras i övningar om värdetabeller och funktionskurvor. Slutligen genomgås hur man skriver egna klassmetoder och skapar egna paket. Alla bör göra de flesta övningarna t.o.m sidan 25. Några av dessa (Klocka, Tärning) ligger som grund för kommande övningar i senare kapitel. Övningarna om värdetabeller och kurvor rekommenderas. Du lär dig tekniken för att överföra x- och ykoordinater i en graf till en skärmbild. Gör övningarna om klassmetoder och paket om du har speciellt intresse. 265338508 © Ove Lundgren 2 Kap 7: Sid 3 Javas klassbibliotek Arv När du skapar en klass, MinApplet, ärver du från en redan befintlig klass Applet. Den befintliga klassen Applet ärver i sin tur från en annan befintlig klass som heter Panel. Denna ärver i sin tur från en klass som heter Container, som ärver från en klass vid namn Component, vilken (slutligen) ärver från ”ur-klassen” Object. Så här alltså: Object Component Container Panel Applet java.lang java.awt java.applet MinApplet Alla klasser ärver från klassen Object. För exempelvis klasserna Button, Label och TextField ser hierarkin ut så här: Object Component Button Label TextComponent TextField 265338508 © Ove Lundgren 3 Kap 7: Sid 4 Klassbiblioteket, Java API (= Java Application Programming Interface) De "färdiga" java-klasserna följer med JDK och är lagrade i "paket" (packages): Klassen Applet ovan finns i paketet java.applet När man skriver klassens namn tar man ofta med paketets namn också, t ex java.applet.Applet Klassen Object ovan finns i paketet java.lang så klassens "fullständiga" namn är java.lang.Object Övriga klasser ovan finns i paketet java.awt (awt = Abstract Window Toolkit) Exempelvis skrivs alltså klassen Button med "paket-tillhörighet" så här: java.awt.Button Alla klasser måste importeras - utom de klasser som tillhör paketet java.lang Utöver klasserna i JDK finns "färdiga klasser" från andra leverantörer. Övning: Dokumentation Alla JDK:s klasser med tillhörande fält och metoder finns beskrivna i html-dokument som levereras med JDK. I mappen ...\jdk...\docs\api\ finns filen packages.html Öppna den i en webläsare! (Se till att du öppnar rätt fil. Det finns många med liknande namn.) En lista över alla paket visas Klicka på package java.applet Innehållet i paketet java.applet visas. Vi känner igen klassen Applet (Vi har också använt interfacet Audioclip ) Klicka Applet En hierarki med alla superklasserna till klassen Applet visas, med klassernas namn och "paket"-tillhörighet. Rulla ned sidan till Method index Vi känner igen ett antal metoder som vi använt, bland andra init()och showStatus() Klicka på showStatus En beskrivning av metoden visas… Återvänd till början av Class java.applet.Applet-sidan (Övningen fortsätter på nästa sida… ) 265338508 © Ove Lundgren 4 Kap 7: Sid 5 En applet har, som bekant, metoden paint() Varför hittar vi inte den? Jo den är ärvd från en av superklasserna. På föregående sidan återvände du till java.applet.Applet Klicka nu på superklasserna, det vill säga java.awt.Panel, java.awt.Container osv och ta reda på vilken klass som, "från början", äger metoden paint() Vi hittar paint() i klassen Container Klicka på paint() och läs om den metoden. Återvänd sedan till sidan Java API Packages: Klicka All Packages högst upp till vänster Klicka nu package java.awt Rulla ner till Class index Du känner igen många klasser: Button, Color, Font, Image, Label, TextField med flera Klicka på några kända klasser. Leta upp metoder som vi använt (Under Method index) Ibland hittar man inte en metod. Då får man leta i superklasserna… I klasserna Color och Font känner du igen en del av innehållet i Field index Studera också "Constructor index" för några klasser, t ex TextField och Color. När ett nytt objekt skapas (med new, du vet…) så anropas ju konstruktorn som skapar objektet. Man kan ofta välja mellan olika konstruktorer. Det som står efter new kan se lite olika ut beroende på vilken konstruktor vi väljer när vi skapar objektet. Constructor index är en sammanställning över möjliga konstruktorer. Exempel: När vi skapade textfält använde vi t ex konstruktorn TextField(int) - så här: TextField inruta; inruta = new TextField(10); (Detta ger ett textfält som rymmer 10 tecken.) Men ett textfält kan också skapas t ex med konstruktorn TextField(String) - så här: TextField inruta; inruta = new TextField("Kalle"); (Då skapas fältet med texten "Kalle" inlagd och i detta fall 5 tecken brett ) Återvänd till sidan Java API Packages Undersök paketet java.lang. Har vi använt någon klass i det paketet? (Du bör hitta String, Integer, Object) Högst upp på alla sidor i API-dokumentationen finns länken Class Hierarchy Klicka denna. Studera hur sidan Class Hierarchy är uppbyggd. Leta t ex upp klassen Applet och följ dess superklasser ända upp till klassen Object Högst upp på alla sidor i API-dokumentationen finns länken Index Klicka denna. Sidan Index of all Fields and Methods visas (Det kan ta lite tid att ladda in denna sida…) Här finns alla fält och metoder i bokstavsordning… I fortsättningen: Ta som vana att gå in i API-dokumentationen när du stöter på en ny klass eller metod och "forska": I vilket paket finns klassen? Vilka klasser är dess superklasser? Vilken klass tillhör metoden? 265338508 © Ove Lundgren 5 Kap 7: Sid 6 Allmänt om metoder Vi repeterar olika typer av metoder, vad som menas med överlagring och överskuggning och vad en klassmetod är. Begreppen har behandlats i tidigare kapitel. Metoder av typen void, utan parametrar Metoden utför något - men den är void, den lämnar inte något värde. Metoden är definierad utan parametrar. Den kräver alltså inga argument vid anropet. Exempel: Metoden rulla() definieras i en klass så här: public void rulla() { // beskrivning vad som ska göras... } Ett objekt (t ex bollen) som skapas utifrån klassen äger förstås metoden. Metoden anropas med bollen.rulla(); Exempel: Metoden show() är definierad i klassen Frame public void show() { // definierad av java-konstruktörerna hos Sun } Om vi har ett Frame-objekt med referensen f så visas objektet med anropet f.show(); Exempel: Metoden init() definieras i en klass (en applet) så här: public void init() { inruta = new TextField(10); roed = new Color(255,0,0); // etc ... } Metoden anropas automatiskt av webbläsaren när appleten startar … (Om vi tänker oss att webbläsaren kallar appletobjektet för x så utförs alltså satsen automatiskt vid start…) 265338508 © Ove Lundgren x.init(); 6 Kap 7: Sid 7 Metoder av typen void, med parametrar Metoden utför något - men den är void, den lämnar inte något värde Metoden är definierad med parametrar. Den kräver alltså ett eller fler argument vid anropet Exempel: Metoden rulla() definieras i en klass så här: public void rulla (int n) { // beskrivning vad som ska göras... } parameter argument Ett objekt (t ex olle) som skapas utifrån klassen äger metoden. Metoden anropas med argument, t ex: bollen.rulla(12); Exempel: Metoden paint() definieras i en klass (en applet) så här: public void paint(Graphics g) { g.drawString("Hej",50,100); // etc ... } Metoden paint(grafobj); anropas automatiskt då applet skapas. grafobj är det Graphics-objekt som är knutet till appleten Exempel: Metoden drawOval() definieras i klassen Graphics public void drawOval( int x, int y, int b, int h ) { // definierad av java-konstruktörerna hos Sun } 4 parametrar Om g är ett Graphics-objekt kan metoden anropas med t ex: g.drawOval(50,100,150,150); 4 argument Exempel: Metoden setBackground() definieras i klassen Component (och ärvs sedan av klassen Applet) public void setBackground(Color c ) { // definierad av java-konstruktörerna hos Sun } Metoden kan anropas med: this.setBackground(farg) där farg är ett Color-objekt När ett objekt anropar en egen metod sätter man this framför punkten. ( Ordet this kan utelämnas - det är då underförstått att det är en egen metod som anropas. ) 265338508 © Ove Lundgren 7 Kap 7: Sid 8 Icke-void-metoder En icke-void-metod kan vara definierad med eller utan parametrar. En icke-void-metod returnerar alltid ett värde. Icke-void-metoder kallas ofta funktioner. Exempel: Metoden (funktionen) volym() definieras i en klass t ex så här: public double volym(int n) // i detta fall returneras ett flyttal { // beskrivning vad som ska göras... return v; } Ett objekt (t ex bollen) som skapas utifrån klassen äger metoden. Metoden anropas t ex så här: vol = bollen.volym(12); eller System.out.println( bollen.volym(12)); Exempel: Metoden (funktionen) getText() definieras i klassen TextComponent (och ärvs av TextField) public String getText() { // definierad av java-konstruktörerna hos Sun return s; // Sträng s är innehållet i det aktuella TextField-objektet } Om vi har skapat ett TextField-objekt inruta, och namn är ett String-objekt, så kan metoden anropas: namn = inruta.getText(); Överskuggning av metoder När vi skriver en applet så ärver vi från klassen Applet. Detta innebär att ett antal metoder redan finns, som paint(), init() med flera Vad händer då om vi definierar en metod paint() i vår applet, så här: public void paint(Graphics g) { g.drawOval(12,20,30,40); // och så vidare } Jo den ursprungliga paint()-metoden ersätts av den nya... Detta kallas överskuggning (override, omdefiniera...) Överlagring av metoder Metoder med samma namn men med olika antal och/eller typ av parametrar kallas överlagrade metoder. 265338508 © Ove Lundgren 8 Kap 7: Sid 9 Klassmetoder Normalt anropar vi en metod via ett objekt, exempelvis inruta.getText(); Här har vi ett TextField-objekt, inruta, och vi använder metoden getText() som är definierad i den klassen (eller, som i detta fall, i någon av dess superklasser) En klassmetod (ibland kallad statisk metod) är en metod som kan användas direkt, utan att man först har skapat ett objekt. Vi har redan använt några sådana metoder: Integer.parseInt( ... ) Prompt.heltal( ... ) Vi behöver inte skapa ett Integer-objekt eller Prompt-objekt för att använda metoderna... Man skriver helt enkelt klassens namn följt av metodnamnet (med en punkt emellan) Man kan säga att en klassmetod tillhör klassen som helhet – inte de enskilda objekten. Integer är en klass som innehåller en rad metoder för hantering av heltal Prompt är en klass med metoder för inmatning av tal i konsolprogram (Tillhör detta läromedel, ej JDK) En metod blir en klassmetod om den deklareras med nyckelordet static Vi har definierat en statisk metod, main, vid flera tillfällen - när vi skrivit javaprogram: class KonsolProg { public static void main( String args[] ) { ... } } Metoden KonsolProg.main( ) anropas (av tolken java.exe ) vilket innebär att konsolprogrammet startar. 265338508 © Ove Lundgren 9 Kap 7: Sid 10 Metoderna i klassen Math Det finns en javaklass som heter Math. Den tillhör java.lang-paketet (Fullständiga klassnamnet är alltså: java.lang.Math) (Klassen behöver således inte importeras.) Denna klass innehåller en rad metoder (funktioner) för matematik. Alla metoder är klassmetoder (vi behöver inte skapa Math-objekt först...) Klassen har också två statiska fält (konstanter) för de intressanta talen och e I sammanställningen nedan är x och y flyttal / decimaltal (double), medan i och j är heltal (int) Du bör kunna använda Math.PI nedan samt de fyra därpå följande metoderna. Lär dig de övriga om du känner till motsvarande begrepp i matematiken. Metod / Fält Math.PI Returnerar talet (3.14159...) Returtyp double Exempel y = Math.PI*x*x; y är arean hos en cirkel med radien x Math.sqrt(x) Kvadratroten ur talet x double y = Math.sqrt(25.0); y får värdet 5.0 Math.pow(x,y) ”x upphöjt till y”, double y = Math.pow(2.0 , 3.0); y får värdet 23 = 8.0 Math.random() ett slumptal mellan 0 och 1 (egentligen 0 slump < 1) double Math.exp(x) ”e upphöjt till x” , j = (int)(Math.random()*6 ) + 1; j blir här ett av talen 1, 2, 3, 4, 5 eller 6 (En "tärning" alltså! Se avsnitten om slumptal!) y = Math.exp(2.0); y får värdet e2 ( 7,389....) Math.E talet e (2,718...) double y = Math.E; y får värdet e (2,718…) Math.log(x) naturlig logaritm för x, ln x double y = Math.log(5.0); y = ln 5 (1,609...) Math.sin(v) sinusvärdet, sin v double y = Math.sin(2.0): y = sin 2 (0,909...) OBS! argumentet i radianer! Math.cos(v) cosinusvärdet cos v double Math.tan(v) tangens tan v double Math.atan(x) arctangens arctan v double xy double ex (omvändning till tangens) Math.abs(x) absolutbeloppet |x| double Math.abs(i) absolutbeloppet |i| int y = Math.arctan(1.0) y = arctan 1 (y blir / 4 rad = 0,785 rad, dvs 45o) Vinkeln / 4 har ju tangensvärdet 1 y=Math.abs(-1.75); y får värdet 1,75 i = Math.abs(7); i får värdet 7 Bra att minnas i sammanhanget: Avhuggning till heltal får vi genom att göra en cast: i = (int)x; Gör om en sträng till heltal: t = Integer.parseInt(s) ; Gör om tal till sträng: s 265338508 © Ove Lundgren = t + ”” ; 10 Kap 7: Sid 11 Övning: Testa Math // Se till att Prompt.class finns i samma mapp class Mattetest { public static void main( String args[] ) { double r, x, y, z, rot,area ; int tarning, i, j; System.out.println("Testar pi:"); r = Prompt.decimaltal("Skriv radien "); area= Math.PI*r*r; System.out.println("Arean är " + area); System.out.println(); System.out.println("Testar roten ur:"); x = Prompt.decimaltal("Mata in ett tal "); rot= Math.sqrt(x); System.out.println("Kvadratroten är " + rot); System.out.println(); System.out.println("Testar upphöjt till:"); x = Prompt.decimaltal("Vilken bas? "); y = Prompt.decimaltal("Vilken exponent?"); z = Math.pow(x,y); System.out.println(x +" upphöjt till " + y + " är " + z); System.out.println(); System.out.println("Testar avhuggning till heltal:"); x = Prompt.decimaltal("Skriv ett tal med decimaler "); i = (int)x ; // här görs en cast System.out.println("Närmast mindre heltal är " + i); System.out.println(); System.out.println("Testar talet e:"); System.out.println("Talet e " + Math.E); x = Prompt.decimaltal("Till vilken exponent ska e upphöjas? "); System.out.println("e upphöjt till "+ x + " är " + Math.exp(x) ); System.out.println(); System.out.println("Testar naturliga logaritmen:"); x = Prompt.decimaltal("Skriv ett tal "); System.out.println("Naturl. log. för " + x + " är " + Math.log(x)); System.out.println(); System.out.println("Testar trigonometri:"); x = Prompt.decimaltal("Skriv en vinkel i radianer "); System.out.println("Sinusvärdet är " + Math.sin(x)); System.out.println("Cosinusvärdet är " + Math.cos(x)); System.out.println("Tangensvärdet är " + Math.tan(x)); System.out.println(); System.out.println("Testar absolutbelopp:"); x = Prompt.decimaltal("Skriv ett tal (gärna negativt) "); System.out.println("Talets absolutbelopp är " + Math.abs(x)); i = Prompt.heltal("Skriv ett heltal (gärna negativt)"); System.out.println("Talets absolutbelopp är " + Math.abs(i)); } } Kopiera (eller skriv av) ovanstående kod. (Ett enkelt konsolprogram för att testa…) Spara som Mattetest.java i mappen X\java\Javagrunder Kompilera och kör. Testkör några gånger. Kom ihåg att använda punkt (och inte komma) som decimaltecken när du skriver in decimaltal. 265338508 © Ove Lundgren 11 Kap 7: Sid 12 Övning: Math i API Leta upp klassen Math i API-dokumentationen Läs om ovan nämnda metoder och fält Övning: Rot-tabell Gör en applet som visar kvadratroten ur talen 1 – 10. Spara som RotTabell i mappen X\java\RotTabell Försök själv. Kika nedan om du kör fast…. import java.applet.*; import java.awt.*; public class RotTabell extends Applet { double y; public void paint(Graphics g) { g.drawString("x" , 50, 50); g.drawString( "Roten ur x" , 100,50); g.drawLine(50,55,200,55); for(int x = 1 ; x <= 10; x++) { g.drawString(x + "" , 50 , 50 + 20 * x ); y = (double) x; g.drawString(Math.sqrt( y ) + "" , 100, 50 + 20 * x ); } } } En kommentar till satsen g.drawString(x + "" , 50 , 50 + 20 * x ); Första x-värdet (x=1) kommer att skrivas i position (50, 70) Nästa x-värde (x=2) kommer att skrivas i position (50, 90) och så vidare… 265338508 (eftersom 50 + 20 * 1 =70) (eftersom 50 +20 *2 =90) © Ove Lundgren 12 Kap 7: Sid 13 Trigonometriska övningar Övning: Klassen Klocka I nedanstående applet, VisaKlocka, instansieras ett objekt av klassen Klocka Klockan instansieras med mittpunkten (150,150) och diametern 100 pixels. Metoden setTid(0) sätter tiden till 0 (noll) sekunder. Metoden visa(g) ritar klockan i appleten. import java.awt.*; import java.applet.Applet; public class VisaKlocka extends Applet { Klocka k; public void init() { k = new Klocka(100, 150,150 ); k.setTid(0);} public void paint(Graphics g) { k.visa(g); } } Klockan har alltså bara en visare (visar sekunder) (som en kronometer) Skriv klassen Klocka. Instansvariabler: diam, x, y, sek Konstruktorn ger värden på x och y (klockans mittpunkt) samt diam (dess diameer) Med metoden setTid(int s) sätts det antal sekunder som klockan ska visa. Med metoden visa(Graphics g) ska klockan ritas. Se figur: Om klockans medelpunkt är (x ,y) och visarens längd är r så får (i matematiken) punkten P koordinaterna: px = x + r * cos v py = y + r * sin v Vinkeln v beror på antalet sekunder. En sekund motsvarar ju 360o/60 P r v eller 2/60 (x,y) Försök skriva klassen Klocka på egen hand (Du får nog ”trixa” lite för att få klockan att gå rätt…) På nästa sida finns ett lösningsförslag… 265338508 © Ove Lundgren 13 Kap 7: Sid 14 import java.awt.*; public class Klocka { private int diam, x, y, sek; public Klocka(int d, int a, int b) { diam = d; x = a; y = b; } public void setTid(int s) { sek = s; } public void visa(Graphics g) { g.drawOval(x-diam/2,y-diam/2,diam,diam); // klockans periferi g.fillOval(x-2,y-2,4,4); // mittpunkten double v = - sek*2*Math.PI/60 + Math.PI/2; // se nedan int r = diam/2-3; // visarens längd int px =x + (int)(r*Math.cos(v)); // x-koordinat för punkten P int py =y - (int)(r*Math.sin(v)); // se nedan g.drawLine(x,y,px,py); } } Satsen double v = - sek*2*Math.PI/60 + Math.PI/2; Minustecken här, annars går klockan baklänges! En vridning medurs ger ju en negativ vinkel i matematiken… Vi lägger till Math.PI/2, det vill säga 90o, så att klockan pekar på ”norr” vid tiden noll sekunder… Satsen int py = y - (int)(r*Math.sin(v)); beräknar y-koordinaten för punkten P Minustecken här eftersom y-koordinater växer nedåt i datagrafiksammanhang… Spara filerna VisaKlocka.java och Klocka.java i mappen X\java\Klocka Kompliera. Skriv en html-fil och provkör! (Klockan visas, men står stilla…) Övning: Klockan tickar Lägg till en knapp. Varje gång du trycker på knappen ska klockan ticka fram fem sekunder. 265338508 © Ove Lundgren 14 Kap 7: Sid 15 Övning: En Stjärn-klass Studera denna applet: import java.awt.*; import java.applet.*; public class VisaStar extends Applet { Star s1, s2; public void init() { s1 = new Star(50, 12); // Diameter 50, 12 ”uddar” s2 = new Star(100, 24); // Diameter 100, 24 ”uddar” s1.setPos(50,50); // Stjärnans placering s2.setPos(150,150); // Stjärnans placering } public void paint(Graphics g) { s1.visa(g); // Stjärna visas s2.visa(g); // Stjärna visas } } Appleten instansierar och visar två objekt av klassen Star, så här: Den lilla stjärnan har ”diametern” 50 pixel och visar 12 ”uddar” Den stora stjärnan har ”diametern” 100 pixel och visar 24 ”uddar” Skriv klassen Star.java P r Använd en loop. Låt vinkeln v öka för varje varv. Rita linje från medelpunkten till punkten P varje varv. P.s koordinater är ( r * cos v , r*sin v ) där r är halva diametern 265338508 © Ove Lundgren v 15 Kap 7: Sid 16 Lösningsförslag: import java.awt.*; public class Star { private int diam, x, y, antal; public Star(int d, int a) { diam = d; antal= a; } public void setPos(int x, int y) { this.x = x; this.y = y; } public void visa(Graphics g) { for(double v = 0.0; v < 2*Math.PI; v = v + 2 * Math.PI/antal) { int a = (int)(diam/2*Math.cos(v)); int b = (int)(diam/2*Math.sin(v)); g.drawLine(x,y, x+a,y-b ); } } } Skriv in, spara och kompilera klasserna Visastar och Star. Spara i mappen X\java\Star Exekvera! Testa olika storlekar och antal ”uddar” på stjärnorna… 265338508 © Ove Lundgren 16 Kap 7: Sid 17 Experiment med slumptal Övning: Konsolprogram som visar slumptal Skriv in denna kod. Spara som SlumpTest.java i mappen X\java\Slump Kompilera och kör. class SlumpTest { public static void main( String args[] ) { double slump ; int i; for(i=1;i<=12;i++) { slump= Math.random(); System.out.println("Slumptal nummer " + i + ": } " + slump); } } Funktionen Math.random() slumpar ett flyttal. Variabeln slump tilldelas detta flyttal. 0 slump < 1 Satserna ingår i en for-loop. Det hela upprepas 12 gånger. Övning: Tipsrad Ändra koden för klassen SlumpTest. Kalla klassen class Tipsrad. Spara som Tipsrad.java Skriv om koden inne i loopen så att om slump < 0,4 så skrivs strängen "1 annars om slump < 0,8 så skrivs " X " annars skrivs " 2" " Gör så att loopen körs 13 gånger. Spara igen. Kompilera. Kör. Resultatet blir en tipsrad. Experimentera: Ändra t ex så att sannolikheten för bortavinst (2:a) ökar Övning: Applet med tipsrad Bygg en applet som har en knapp. När du trycker på knappen ska en ny tipsrad visas. 265338508 © Ove Lundgren 17 Kap 7: Sid 18 Slumpa heltal Betrakta satserna nedan: ( slump är double, t är int ) slump = Math.random(); ger ett tal i intervallet 0.0 till 0,999999999999… slump = 6 * Math.random(); ger ett tal i intervallet 0.0 till 5,99999999… t = (int)(6 * Math.random()); ger ett heltal i intervallet fr o m 0 t o m 5 t = (int)(6 * Math.random()) + 1; ger ett heltal i intervallet fr o m 1 t o m 6 Den sista satsen ger alltså ett heltal som är 1, 2, 3, 4, 5 eller 6. En tärning med andra ord!! Allmänt gäller formeln t = (int)(n * Math.random() ) + a; n = antalet tänkbara slumptal a = det minsta tänkbara slumpade talet Exempel: Slumpa ett tal i intervallet fr o m 0 t o m 255 (det vill säga 256 stycken tänkbara tal). Formel: t = (int)(256 * Math.random() ) ; Övning: Konsolprogram som slumpar heltal Ändra koden för klassen SlumpTest. Kalla klassen class SlumpaHeltal. Spara som SlumpaHeltal.java Deklarera heltalsvariablen t Skriv om koden inne i loopen så att tolv tal i intervallet 0 – 255 visas Spara igen. Kompilera. Kör. Övning: Slumpa färg Skriv en applet, Slumpfarg, som har en knapp med tillhörande händelsehantering. I actionPerformed-metoden slumpas tre heltal i intervallet 0 - 255 Sen skapas ett Color-objekt med de tre heltalen som RGB-komponenter Så sätts den nya färgen till bakgrundsfärg. När man trycker på knappen så byter alltså appleten färg! Spara som Slumpfarg.java i mappen X\java\Slumpfarg Övning: Konsolprogram som visar tärning Ändra koden för klassen SlumpTest. Kalla klassen class KonsolTarning. Spara som KonsolTarning.java Deklarera heltalsvariablen t Skriv om koden inne i loopen så att tolv "tärningskast" (tal i intervallet 1 - 6 ) visas. Spara igen. Kompilera. Kör. 265338508 © Ove Lundgren 18 Kap 7: Sid 19 Övning: Applet som visar en tärning En applet, KastaTarning, har en knapp. När man trycker på knappen visas en tärning, t ex: Appleten instanierar ett objekt av typen Tarning med referensen t Tarningsobjektets metod kasta() slumpar och returnerar ett tal i intervallet 1 – 6 Metoden visa(Graphics) visar tärningen med rätt antal prickar… Studera appleten och skriva av (eller kopiera) och spara koden. import java.applet.*; import java.awt.*; import java.awt.event.*; public class KastaTarning extends Applet implements ActionListener { Tarning t; Button butt; int k; public void init() { t = new Tarning(40,40); // tärning i position 40,40 k = t.kasta(); butt = new Button("Kasta!"); butt.addActionListener(this); add(butt); } public void paint(Graphics g) { t.visa(g); g.drawString(”Tärningen visar: ” + k, 40, 110 ); } public void actionPerformed(ActionEvent e) { k = t.kasta(); repaint(); } } Skriv nu klassen Tarning Försök lösa uppgiften på engen hand (På nästa sida finns ett lösningsförslag..) Spara KastaTarning.java och Tarning.java i mappen X\java\Tarning 265338508 © Ove Lundgren 19 Kap 7: Sid 20 import java.awt.*; public class Tarning { private Color farg = Color.blue; private Color prickfarg = Color.yellow; private int a, b; private int p = 5; // prickstorlek private int t; // antal prickar public Tarning(int a1, int b1) { a = a1; b = b1; } public int kasta() { t = (int)(6 * Math.random()) + 1; return t; } public void visa(Graphics g) { g.setColor(farg); g.fillRect(a,b,45,45); g.setColor(prickfarg); switch (t) { case 1: g.fillOval(a+20,b+20,p,p); break; case 2: g.fillOval(a+10,b+10,p,p); g.fillOval(a+30,b+30,p,p); break; case 3: g.fillOval(a+10,b+10,p,p); g.fillOval(a+30,b+30,p,p); break; case 4: g.fillOval(a+10,b+10,p,p); g.fillOval(a+10,b+30,p,p); break; case 5: g.fillOval(a+10,b+10,p,p); g.fillOval(a+20,b+20,p,p); g.fillOval(a+30,b+30,p,p); break; case 6: g.fillOval(a+10,b+10,p,p); g.fillOval(a+30,b+10,p,p); g.fillOval(a+20,b+30,p,p); break; } g.fillOval(a+20,b+20,p,p); g.fillOval(a+30,b+10,p,p); g.fillOval(a+30,b+30,p,p); g.fillOval(a+30,b+10,p,p); g.fillOval(a+10,b+30,p,p); g.fillOval(a+20,b+10,p,p); g.fillOval(a+10,b+30,p,p); g.fillOval(a+30,b+30,p,p); } } 265338508 © Ove Lundgren 20 Kap 7: Sid 21 Förvandla sträng till decimaltal I ett tidigare kapitel byggde vi applets där man kunde skriva in tal i textfält (TextFields) I ett textfält är ju allt strängar, så vi fick lov att omvandla en inmatad sträng (t ex "123") till ett heltal (123) Vi använde då metoden Integer.parseInt( ) I en övning gällde det att mata i en cirkels radie i textfältet inruta för att sedan överföra värdet till heltalsvariabeln radie. Satsen kunde se ut så här: radie = Integer.parseInt( inruta.getText() ); ( java.lang.Integer är en klass som innehåller en rad metoder för hantering av heltal ) Vi vill nu kunna mata in en sträng, t ex "123.55" i textfältet inruta och få strängen omvandlad till ett decimaltal (ett flyttal) (123.55) som sedan tilldelas double-variabeln r I Java2 finns en metod för detta. Vi kan vi skriva så här: r = Double.parseDouble( inruta.getText() ); I Java 1.1 får vi sätta samman fler metoder för samma sak. Vi kan vi skriva så här: r = Double.valueOf(inruta.getText().trim().replace(',','.')).doubleValue(); (Här har vi dessutom utnyttjat metoden replace som byter ut ett tecken mot ett annat: Om man råkar skriva ett kommatecken som decimalttecken så byts det ut mot en punkt. Java kräver ju punkt som decimaltecken) För dig som vill fördjupa dig i satsen följer här en "dissektion". Vi börjar ”inifrån”: inruta är ett TextField-objekt TextField-objekt har en metod (en funktion) getText() som "fångar" det som står i textfältet och returnerar det som en sträng, ett String-objekt. Så inruta.getText() är ett String-objekt. String-objekt har en metod (en funktion) trim() som "hugger av" eventuella blanktecken i början och slutet av strängen och returnerar en "trimmad" sträng. Så inruta.getText().trim() är ett String-objekt. String-objekt har en metod (en funktion) replace(t1,t2) som byter ut eventuella förekomster av tecknet t1 i strängen mot tecknet t2 och returnerar denna nya variant av strängen. Så inruta.getText().trim().replace(',','.') är ett String-objekt där alla eventuella komma-tecken bytts ut mot punkter. Det finns en klass som heter Double. (Det är inte den primitiva variabeltypen double utan en klass Double) I klassen finns en rad metoder för flyttalshantering. (I klassen Integer finns motsvarande för heltal) Klassen Double har en metod (en funktion) valueOf(String) Den funktionen tar ett String-objekt som argument och returnerar ett objekt tillhörigt klassen Double. Så Double.valueOf(inruta.getText().trim().replace(',','.')) är ett Double-objekt. Double-objekt har en metod (en funktion) doubleValue(). Denna returnerar värdet hos Double-objektet och detta är – äntligen - vårt eftersökta flyttal av den primitiva datatypen double (puh!) Talet tilldelas variabeln r och kan användas i beräkningar… Övning: Cirkel - igen Ta fram filen Cirkel.java (kap 5) Deklarera radie som double i stället för int Använd någon av ovan beskrivan metoder för att ta hand om den radie som matas in i textfältet (Byt alltså ut parseInt-metoden) Du använde förut talet pi = 3.14159 265338508 Byt ut mot Math.PI © Ove Lundgren 21 Kap 7: Sid 22 Antal decimaler i utskrift Talformat Vi har hittills fått lov att stå ut med att flyttalen i våra program visat onödigt många decimaler. Det är på tiden att vi själva kan bestämma antal decimaler som ska visas. Dags att införa talformat! Gör så här: Importera: import java.text.DecimalFormat; // ett nytt paket! Deklarera objekt: DecimalFormat d2, d3, m3; Skapa objekt: d2 = new DecimalFormat("0.00"); // ger 2 decimaler d3 = new DecimalFormat("0.000"); // ger 3 decimaler m3 = new DecimalFormat("0.###"); // ger max 3 decimaler // Ev. nollor på slutet // visas ej... Objekt av klassen DecimalFormat har en metod (en funktion), format(tal) Argumentet (tal) är av typ double Funktionsvärdet blir en sträng som innehåller talet med önskat antal decimaler. Exempel: g.drawString("Arean är " + d2.format(area) , 10,90 ); g.drawString("Omkretsen är " + d3.format(omkrets) , 10,90 ); System.out.println("Slumptal nr " + i + ": Övning: RotTabell - igen Ändra koden i RotTabell.java " + m3.format(slump)); så att talen visas avrundade till två decimaler: import java.text.*; import java.applet.*; import java.awt.*; public class RotTabell extends Applet {double y; DecimalFormat d2; public void init() { d2 = new DecimalFormat("0.00"); // ger 2 decimaler } public void paint(Graphics g) { g.drawString("x" , 50, 50); g.drawString( "Roten ur x" , 100,50); g.drawLine(50,55,200,55); for(int x = 1 ; x <= 10; x++) { g.drawString(x + "" , 50 , 50 + 20 * x ); y = (double) x; g.drawString(d2.format( Math.sqrt( y )) + "" , 100, 50 + 20 * x ); } } } 265338508 © Ove Lundgren 22 Kap 7: Sid 23 Metoder i en applet Metoder som körs automatiskt När vi skriver en applet (t ex MinApplet) så ärvs ett antal metoder från klassen Applet. Flera av dessa metoder körs automatiskt vid olika tillfällen under en applets "liv". I kapitel 4 beskrev vi dessa metoder ungefär så här: init() Körs med automatik när en applet laddas. Här lägger man kod för initialvärden av olika slag. start() Körs automatiskt då en applet visas Här skrivs kod som får appleten att göra något. Appletens init-metod körs första gången appleten visas. Appletens start-metod körs första gången samt varje gång du återvänder till sidan med appleten. paint(Graphics g) Metoden exekveras automatiskt varje gång en applet visas. Metoden har en parameter, en referens till ett Graphics-objekt. Då metoden anropas blir argumentet referensen till appletens egna grafikobjekt stop() Körs automatiskt då man lämnar webb-sidan med appleten destroy() Exekveras automatiskt när man slutar sitt surfpass. I respektive metod skriver man kod för sådant som man vill ska utföras vid respektive tidpunkt. Hittills har du mest omdefinierat init() – och paint()-metoderna. Snart kommer exempel där även övriga metoder överskuggas… paint()-metoden anropas med automatk då appleten visas. Ibland behöver man anropa paint() på nytt för att rita om appletytan. Du har redan sett att man då använder en metod som heter repaint(). Nästa avsnitt handlar just om metoderna paint() och repaint() samt om ytterligare en metod som är inblandad, nämligen update() 265338508 © Ove Lundgren 23 Kap 7: Sid 24 Metoderna paint(), repaint() och update() Metoden paint(Graphics g) är definierad med en parameter som är referens till ett Graphics-objekt. När paint() anropas blir automatiskt argumentet referensen till appletens eget grafiska objekt. (Repetera gärna vad som står om klassen Graphics i kapitel 4) Antag att vi skulle behöva anropa paint(), t ex i actionPerformed()-metoden. (Vi kanske vill att appleten ska ritas om - exempelvis efter en knapptryckning. ) Om vi vill skriva kod, en sats som innebär anrop av paint(), vad ska vi då skriva för argument? this.paint(????); Vi känner ju inte namnet på referensen till det appletens grafiska objekt. Det är en intern referens. Appletobjekt har ytterligare en metod, repaint(), som blir vår räddning. Den anropas utan argument: this.repaint(); Metoden utför just vad vi vill: Appleten ritas om! Låt oss se närmare på vad som händer vid ett repaint()-anrop: Vi måste då först bekanta oss med en metod som heter update() Detta är ytterligare en metod som ärvs från klassen Applet. Den har ett Graphics-objekt som parameter, och så här är den definierad (i princip): public void update(Graphics g) { // Bakgrunden ritas om varvid allt som // eventuellt tidigare uppritats raderas ... // paint() anropas: paint(g); } update() gör alltså följande: Raderar vad som eventuellt redan ritats på appleten - och anropar sedan paint() När metoden repaint() anropas så anropar denna i sin tur metoden update() Det vill säga, allt som eventuellt är ritat på appleten raderas först, och sedan ritas appleten om. repaint() 265338508 update() ev. gammalt raderas paint() © Ove Lundgren 24 Kap 7: Sid 25 Övning: Överskugga update() Ta fram filen FlyttaJumbo.java och påminn dig om hur den fungerade: I action()-metoden finns satsen this.repaint(); Kör appleten. När du trycker på knapparna så försvinner en tidigare ritad Jumbo och en ny Jumbo ritas varje gång! Antag nu att vi vill göra så att en tidigare ritad Jumbo ligger kvar på appleten när en ny Jumbo ritas. Hur ska vi gå till väga? Naturligtvis genom att göra en egen definition av update() ! Vi överskuggar update() så att den inte gör något annat än anropar paint() I filen FlyttaJumbo.java gör följande tillägg: public void update(Graphics g) { paint(g); } Spara - kompilera - provkör… 265338508 © Ove Lundgren 25 Kap 7: Sid 26 Metoder som returnerar värde Vi ska experimentera lite med egendefinierade icke-void-metoder (funktioner) Övning: Kvadrattabell Detta är en applet som skriver ut en kvadrattabell ( x2 )på talen 1 – 10 (Påminner mycket om appleten som skrev ut kvadratrötter…) import java.applet.*; import java.awt.*; public class KvadratTabell extends Applet { public void paint(Graphics g) { g.drawString("x" , 50, 50); g.drawString( "Kvadraten på x" , 100,50); g.drawLine(50,55,200,55); for(int x = 1 ; x <= 10; x++) { g.drawString(x + "" , 50 , 50 + 20 * x ); g.drawString( x * x + "" , 100, 50 + 20 * x ); } } } Skriv in och testa! Spara KvadratTabell.java i mappen X\java\KvadratTabell I klassen Math finns en funktion som beräknar kvadratroten ur ett tal (Math.sqrt) Det finns däremot ingen funktion som beräknar kvadraten på ett tal. Låt oss skriva en egen sådan metod och utnyttja den i appleten ovan! Ändra ovanstående kod till: import java.applet.*; import java.awt.*; public class KvadratTabell extends Applet { private int kvadrat(int i) { Här deklareras return i * i ; funktionen } public void paint(Graphics g) { g.drawString("x" , 50, 50); g.drawString( "Kvadraten på x" , 100,50); g.drawLine(50,55,200,55); for(int x = 1 ; x <= 10; x++) { g.drawString(x + "" , 50 , 50 + 20 * x ); g.drawString( this.kvadrat(x) + "" , 100, 50 + 20 * x ); } } Här sker anropet } Här har vi deklarerat en egen private funktion i appleten med namnet kvadrat. Metoden tar ett heltal som parameter och lämnar ett heltalsvärde. Metoden anropas med heltalsargumentet x 265338508 © Ove Lundgren 26 Kap 7: Sid 27 Det är vanligt att man på detta sätt skriver egna metoder/funktioner. Antag t ex att samma beräkning ska utföras många gånger i ett program. Då är det bekvämt att lägga beräkningarna i en funktion som sedan anropas varje gång beräkningen behöver utföras. Övning: En värdetabell Här är en variant. Deklarera funktionen f(x) = 0,5x2 + x 2 Deklarera alltså funktionen double f(double x) som returnerar ovanstående funktionsvärde. Gör en värdetabell som visar funktionsvärden i intevallet 2 x 2 i steg om 0,25 Använd en while-loop. Försök att skriva appleten på egen hand. Kika nedan om du får problem. import java.applet.*; import java.awt.*; public class VardeTabell extends Applet { double x, xstart, xslut, steg; int rad; double f(double a) { return 0.5 * a * a + a - 2 ; } public void init() { xstart = -2.0; xslut = 2.0; steg = 0.25; rad = 70; // för radmatning i appeten } public void paint(Graphics g) { g.drawString("x" , 50, 50); g.drawString( "f(x)" , 100,50); g.drawLine(50,55,200,55); x = xstart; while(x < xslut + steg/2) { g.drawString(x + "" , 50 , rad ); g.drawString( this.f(x) + "" , 100, rad ); rad = rad + 20; x = x + steg; // stega fram sist i while-loopen } } } Spara VardeTabell.java i mappen X\java\VardeTabell Visa i en applet som är 400 x 400 pixels 265338508 © Ove Lundgren 27 Kap 7: Sid 28 Övning: En funktionskurva Ovanstående program kan du använda som utgångspunkt i ett program som ritar en funktionskurva. Vi behöver då ”översätta” x- och f(x)-värden till punkter på skärmen. Vi inför heltalsvariablerna ox och oy som är koordinater för den punkt på appletytan där origo ska ligga. Vidare införs heltalsvariabeln skala som anger hur många pixels det ska vara mellan två heltal på x- respektive y-axeln. Dessutom behöver vi heltalsvariabler som används när vi ska rita kurvan. Vi kallar dem a1 och b1 (a1,b1) (ox,oy) skala En punkt (x, f(x)) på kurvan motsvaras av punkten (a1, b1) på appletytan. Om exempelvis x = 2 så får vi a1 så här: a1 = ox + 2 * skala Allmänt: a1 = ox + x * skala Eftersom a1 är ett heltal och det ingår ett flyttal (x) i vänsterledet måste vi dessutom göra en ”cast”. Javasatsen blir: a1 = ox + (int)(x*skala); På motsvarande sätt får vi y-koordinaten: b1 = oy – (int)( f(x) * skala); Minusteckent kommer sig av att y (tvärtemot i matematiken) växer ”nedåt” i datagrafiska sammanhang. När vi ritar kurvan använder vi drawLine()-metoden, så kurvan kommer att byggas upp av korta sträckor. Vi inför därför även heltalskoordinaterna a2 och b2 så att vi kan hålla reda på två punkter åt gången. Skriv appleten Kurva. Du får hjälp med det programavsnitt som ritar kurvan: x = xstart; a1 = ox + (int)(x*skala); // Den första punktens x-koordinat på appleten b1 = oy - (int)(f(x)*skala); // Den första punktens y-koordinat på appleten x = x + steg; // Nästa x-värde ger ny punkt while(x < xslut + steg/2) { a2 = ox + (int)(x*skala); // Nya punktens x-koordinat på appleten b2 = oy - (int)(f(x)*skala); // Nya punktens y-koordinat på appleten g.drawLine(a1,b1,a2,b2); // Ritar sträckan från ”gammal” till ”ny” punkt a1=a2; b1=b2; // Den ”nya” punkten blir ny ”gammal” punkt x = x + steg; // Stega fram till nästa x-värde sist i while-loopen } Spara Kurva.java i mappen X\java\Kurva Gör så att koordinataxlar (och kanske skalstreck) visas! Byt till någon annan funktion. Testa trigonometriska och exponentiella funktioner. Om kurvan blir ”kantig” får man ge variabeln steg ett mindre värde. Genom att ändra variabeln skala får man olika storlek på kurvan. Alternativa värden på xstart och xslut visar kurvan i andra intervall. 265338508 © Ove Lundgren 28 Kap 7: Sid 29 Egna klassmetoder En klassmetod (ibland kallad ”statisk” metod) kan användas utan att man först behöver skapa ett objekt. (Motsvarande för klassvariabler) Övning: Klassmetoder I kapitel 2 (avsnittet ”Klassmetoder och klassvariabler”) fanns en övning där du skulle skriva in följande kod public class Matte { public static int sqr(int x) { return x*x; } public static final double pi = 3.14159; } Här deklarerade vi den statiska metoden sqr(int x) som (också) beräknade kvadraten på ett heltal. Dessutom deklarerade vi klassvariabeln pi. Denna var dessutom final vilket betydde att den inte kunde ändras (dvs pi är en konstant) Testa metoden sqr() i din applet Kvadrattabell: Kopiera filen Matte.class till mappen där du har appleten KvadratTabell (Om du inte har filen: Skriv in koden ovan, spara och kompilera…) I appleten KvadratTabell: Ersätt metoden this.kvadrat(x) med Matte.sqr(x). Spara – kompilera –provkör. Klassen Matte fungerar på samma sätt som JDK-klassen Math Andra klasser kan givetvis använda metoden i Matte – dock under en förutsättning att de ligger sparade i samma mapp! Om du vill komma åt Matte från andra klasser måste den vara sparad i en mapp som ingår i classpath-listan 265338508 © Ove Lundgren 29 Kap 7: Sid 30 Övning: Metod som omvandlar sträng blir flyttal Om du använder Java 1.1: Skriv en metod, toFlyttal(String s) , som tar en sträng som argument och som returnerar motsvarande flyttal. Metoden ska vara publik och statisk och ligga i klassen Matte. Exempel: Vid anropet double d = Matte.toFlyttal(”17.67”) ska d få värdet 17.67 Utnyttja Double.valueOf(s.trim().replace(',','.')).doubleValue(); Testa din metod i appleten Cirkel: radie = Matte.toFlyttal( inruta.getText() ); Övning: Max3 Klassen Math har en funktion, max, som returnerar det största av de två tal som anges som argument. Skriv en metod, max3, som returnerar det största av de tre heltal som anges som argument. Metoden ska vara publik och statisk ligga i klassen Matte. Exempel: Vid anropet int t = Matte.max3(12,5,18); ska t får värdet 18 Skriv ett (enkelt konsol-) program, MaxTest.java, för att testa din metod. Spara programmet i X\java\javagrunder Hjälp: Algoritm för att ta fram det största talet av tre: om a > b om a>c max = a annars max = c annars om b > c max = b annars max = c 265338508 © Ove Lundgren 30 Kap 7: Sid 31 Paket Om du vill att din klass ska tillhöra en package (ett paket), gör du så här: package mittpaket; // klassen Matte tillhör paketet mittpaket public class Matte { public static int sqr(int i) { // metoddefinition enligt ovan } public static double toFlyttal(String s) { // metoddefinition enligt ovan } public static int max3(int a, int b, int c) { // metoddefinition enligt ovan } } Filen sparas med namnet Matte.java och kompileras till Matte.class Filen Matte.class ska ligga i en mapp med namnet mittpaket. Den mappen ska i sin tur ligga i JDKs lib-mapp eller i en mapp till vilken du satt CLASSPATH När du sen ska använda någon av metoderna måste klassen först importeras. Om t ex en applet använder någon av metoderna måste appletens kod inledas med: import mittpaket.Matte; eller import mittpaket.*; Den senare varianten innebär att samtliga ”paketanslutna” klasser i mappen mittpaket importeras (Du kanske har anslutit fler klasser än Matte till paketet…) 265338508 © Ove Lundgren 31