Introduktion till Java (del1) 1
Översikt Att köra Java Kompilator Interpretator Statisk vs. dynamisk variabelbindning Parameter-passing Primitiva datatyper Strängar Programmering tillämpningar och datastrukturer 2 2
Köra Java >> javac MyCode.java Producerar MyCode.class Assemblerkod för JVM >> java MyCode Interpreteras Programmering tillämpningar och datastrukturer 3 3
Program i Java Filstruktur i NetBeans Object Fågel Rovfågel Duva Pingvin Falk Varje klassdefinition i egen fil Biblioteksfiler (paket) Programmering tillämpningar och datastrukturer 4 Man ska ha kompilerat alla ingående filer, och lagt.class-filerna tillsammans. 4
Kompilering källkod kompilator Hello.java Hello.class Javabytekod Programmering tillämpningar och datastrukturer 5 5
Att köra program filsystem RAM CPU cache förinladdning av material som snart kommer att behövas Programmering tillämpningar och datastrukturer 6 Vad innebär det att köra ett program egentligen? Programmet laddas in i RAM (av operativsystemet), sedan överförs kontrollen till det inladdade programmet tills det exekverat färdigt. (Egentligen mer komplicerat. Ex.vis. Så brukar inte hela programmet få plats i RAM (operativsystemet tar ju också plats). Så, OS jobbar med cachen under tiden, försöker förutsäga vilka delar av programmet och andra länkade filer som kommer att behövas den närmaste tiden. Dessa laddas in i cachen. Laddning från cach till RAM mycket snabbare än laddning direkt från filsystemet. Ens program är alltså utspritt över RAM och cache (och filsystemet), och det är ytterst viktigt att rätt del snabbt kan hittas och laddas in i RAM. Naturligtvis snabbare om alla länkar, och referenser hittade, och det som refereras till har blivit fysiskt inlagt på referensens plats i koden. Det är bl.a. detta som kompilatorn gör.) Problemet är att alla referenser inte går att reda ut innan koden körs igång. Dessa delar går alltså inte att förkompilera. Ett annat, minst lika viktigt problem är att olika plattformar (Mac, PC, Unix) kör olika maskinnära språk. Kompilatorn måste alltså översätta.java-filen till helt olika språk, beroende på vilken dator man vill köra programmet på. Javas lösning är att köra mot en gemensam mjukvarudator, som beter sig likadant på alla plattformar, men som implementeras olika, på dessa plattformar. 6
JVM Hello.class Unix Windows Darwin RAM RAM RAM CPU CPU CPU CPU CPU CPU Programmering tillämpningar och datastrukturer 7 Vad som egentligen händer när man kör en.class-fil är att man kör på en mjukvarudator, som i sin tur körs på de olika plattformarna. 7
Mjukvarudator Java Virtual Machine (JVM) Interpreterar Java-program (.class) Finns aldrig några exe-filer Implementeras olika på olika plattformar Interpretering mot dator Olika för olika plattformar Unix, Mac, PC Eg. operativsystemsberoende Solaris, Darwin, Windows Programmering tillämpningar och datastrukturer 8 8
I två steg Kompilering av källkod (.java) Build (flera filer som ska kopplas in) Producerar bytecode (.class) Gör språket Java plattformsoberoende! Möjliggör dynamisk bindning Programmering tillämpningar och datastrukturer 9 Det blir alltså en procedur i två steg, först till javabytekod, sedan till maskinkod (det andra steget körs interpreterat). Varför inte kompilera i två steg? 9
Varför interpreterat? Polymorfism dvs. samma namn på metod i superklass och subklass Ex.vis. i kod för grafik där paint omdefinieras ofta i subklass Objekt skapas on-the-fly under körning Programmering tillämpningar och datastrukturer 10 För att man vill tillåta polymorfism. Men, polymorfism innebär tekniska svårigheter: när kompilatorn ser pelle.flyga(); vet den inte vilken kod som ska kopplas till detta anrop. pelle kanske är deklarerad som Fågel, eller t.o.m. Djur i en lista som ska representera djuren på ett zoo. Så, kompilatorns bästa gissning är att Djur.ät() kommer att behöva utföras. Men, när programmet väl körs kommer pingvin.flyga() att behöva utföras. Detta visar sig endast under körning, varför man inte i förväg kan kompilera ihop en exe-fil. 10
Varför interpreterat? Object element = mylist.getnext(); element.bläddrasidan(42); Omöjligt att i förväg veta vilken metod (= kod) som kommer att behöva exekveras Kräver dynamisk bindning Programmering tillämpningar och datastrukturer 11 Ett annat exempel: Kommer variabeln element att referera till ett objekt av typen Object, eller kanske av typen Litteratur, eller typen Bok? Bläddra betyder olika saker beroende på vilket objekt som ska utföra det (det är olika koder som ska exekveras). Och vilket objekt som ska utföra det (dvs. vilken kod som ska exekveras) beror på vilka vägar genom if-else satser som programmet kommer att ta, vilket i sin tur kan bero på användarinput, etc. Informationen finns i programmet, men kompilatorn skulle behöva tankesimulera programmet för att komma underfund med vilket objekt som i slutändan kommer att hamna i variabeln. Och att låta kompilatorn tankesimulera ett program genom alla dess möjliga förgreningar, är ju inte genomförbart. 11
Variabelbindning Två sätt Bestäms av syntaktiska strukturen hos koden Bestäms av kontrollstrukturen (exekveringsflödet ) Programmering tillämpningar och datastrukturer 12 OK, men, vad är dynamisk bindning för något? Jo, i vårt fall är dynamisk bidning = bindning av metodnamn till metodkropp (= kod) under körning. en sker alltså under körning, därav beteckningen dynamisk. För att ge en kort bakgrund, kan man titta på skillnaden mellan statisk och dynamisk bindning. 12
Variabelbindning (Lisp) (let ((n 1)) (defun addn (z) (add n z))) (let ((n 2)) (addn 3)) Statisk bidning 4 Dynamisk bindning 5 detta n eftersom definitionen sitter i den här omgivningen detta n eftersom anropet sker i den här kontexten Programmering tillämpningar och datastrukturer 13 Vid statisk bindning binds alla fria variabler på basis av hur de är placerade i koden. Så, om n = 1 omger en funktionsdefinition i Lisp, kommer detta värde att gälla för n. Detta helt oberoende av vad som sedan händer vid exekvering. I andra fallet, vid dynamisk bindning, binds inte fria variabler förrän under exekvering. Så, om n sattes till 1 vid definitionstillfället är det ändå inte detta som kommer att gälla. Det Som gäller är hur n sätts innan funktionen anropas (och ska exekveras). Här är alltså n = 2, och det är i detta dynamiska kontext som funktionen exekveras. Notera att nästa gång programmet körs, kanske n = 5. n kan t.o.m. sättas av användaren, precis innan funktionen anropas. 13
Statisk bindning Variabelns värde bestäms av dess position i programmet Närmast omslutande programblock där variabeln är deklarerad Kompilatorn kan bestämma variabelinstans och lägga in i exe-filen Programmering tillämpningar och datastrukturer 14 Så, statisk bindning baseras på kodens struktur, hur variabler, etc. ligger i förhållande till varandra i koden. Här ska en kompilator kunna avgöra värdet på variabler och kopplingen mellan metodnamn och kod genom att analysera programmets utseende (syntaktiska struktur). 14
Dynamisk bindning Variabelns (funktionsnamns) värde inte känt förrän programmet körs Kräver dynamisk bindning Implementeras genom interpretering, dvs. att programmet tolkas en sats i taget Programmering tillämpningar och datastrukturer 15 Dynamisk bindning är nödvändig i Java eftersom metodnamn inte kan associeras till rätt metoddefinition förrän programmet körs. Kompilatorn tittar naturligtvis på vilken datatyp en referensvariabel är deklarerad som, men objektet som de facto refereras med denna variabel kan vid exekvering visa sig vara en subklass av vad som deklarerades (detta är alltså tillåtet i Java). Om kompilatorn fick bestämma (= statisk bindning), skulle den metoddefinition som motsvarar deklarationstypen (eller en definitionen i en superklass till denna) associeras med metodanropet. Detta var inte programmerarens avsikt. Programmeraren vill att den metod utförs som hör till det objekt som just för tillfället råkar refereras med variabeln, trots att den ursprungliga deklarationen säger någonting annat (=dynamisk bindning). Ok, det här var kompilatorbekymmer. Java löser det hela genom att inte tillåta kompilatorn att binda metodkroppen till metodanrop vid kompileringstillfället. Denna bindning skjuter kompilatorn framför sig, och låter interpretatorn ta hand om under exekvering (då det är lätt att se vilket objekt som de facto refereras med en variabel). 15
Använder statisk bindning Fria variabler binds vid definitionstillfället Common Lisp Alla omgivningsvariabler skickas med när funktionen skickas som argument Programmering tillämpningar och datastrukturer 16 Ett språk som använder statisk bindning är Common Lisp. Vanlig LISP däremot kör dynamisk bindning. 16
Java Använder dynamisk bindning Därför körs JVM interpreterat Plussidan: flexibilitet Nackdel: långsam Just-in-time kompilering ger något förbättrad prestanda Programmering tillämpningar och datastrukturer 17 Just-in-time kompilering: Under körning kommer programmet att följa olika förgreningar, beroende på hur villkorsdelen på if-satser faller ut, etc. Har man väl hamnat på ett ställe i programmet, vet man vilka objekt som de facto döljer sig bakom de olika variablerna, och därmed också vilka metoder (=koder) som behöver exekveras ifall man skulle följa samma väg genom programmet en gång till. Man kan förbereda inför nästa gång genom att kompilera de delar av koden som man har följt. Detta förbättrar prestandan avsevärt, förutsatt att samma väg genom programmet kommer att tas flera gånger. 17
Parametrar argument Parameter (formell parameter) vid definition public static int add(int a, int b) { } Argument (aktuell parameter) vid anrop Math.add(3,4) Vid anrop: parametern ska bindas till argumentet (det aktuella värdet) Programmering tillämpningar och datastrukturer 18 OK, nu har vi alltså ett sätt att bestämma vilken metodkropp (= kod) som ska anropas. Nästa steg är att se till att metoden får tillgång till rätt information. Viktigt att veta är om Java kopierar argumenten eller inte. Om man t.ex. skickar en lista till en metod, och metoden vill radera i listan, kommer detta att förstöra anroparens lista också? Först lite grundbegrepp: parameter är det som metoden har i sin definition, argument är det som skickas till metoden vid anrop. 18
Anropssätt Call-by-value Enkel Argumenten evalueras en gång Call-by-name Kan undvika vissa beräkningar Oändliga loopar Odefinierade operationer (delning med 0) Ger ren semantik programkorrekthet Call-by-need Programmering tillämpningar och datastrukturer 19 Call-by-value vida använt, lätt att implementera. 19
Call-by-value misse.sättålder(ålder); Steg1: Evaluera ålder Steg2: Lägg värdet på anropsstacken Steg3: Lämna kontrollen till metoden (tillsammans med en pekare till stacken) Programmering tillämpningar och datastrukturer 20 20
Call-by-name Steg1: Ersätta parameter på alla platser i metod-kroppen med motsvarande argument Steg2: Starta exekvera metoden Steg3: Evaluera argument vid behov Argument kan komma att evalueras flera gånger Oftast onödig extra-beräkning Programmering tillämpningar och datastrukturer 21 Oftast onödig extra-beräkning om samma argument förekommer flera gånger och därför behöver evalueras flera gånger. Om det finns sidoeffekter (ex.vis. att när argumentet evalueras så skrivs viss information till fil), så är det förmodligen meningen att argumentet ska evalueras flera gånger. I annat fall vore det bättre med en mer optimal lösning, typ call-by-need. 21
Skillnad CBV CBN public static void slask(int element, boolean b) { if (b) { System.out.println("Allt är ok"); } else { System.out.println(element); } } public static void main(string[] args) { int[] poäng = new int[10]; slask(poäng[10], true); } Programmering tillämpningar och datastrukturer 22 Oftast bättre chanser att undvika run-time problem med CBN. Hade Java använt CBN hade poäng[10] aldrig evaluerats, och man hade kunnat fortsätta i programmet. Eftersom Java använder CBV, evaluerades poäng[10] (just innan man lämnade över kontrollen till metoden), och detta resulterade i ett run-time exception: ArrayIndexOutOfBounds. 22
Lat evaluering Call-by-need Fördröjd evaluering tills argumentet faktiskt används i metoden Evalueras en gång Kombinerar fördelarna med CBV och CBN Programmering tillämpningar och datastrukturer 23 Är egentligen call-by-name. MEN, första gången en förekomst av parametern påträffas evalueras värdet, och läggs i uppslagstabellen. Nästa gång behöver man bara slå upp värdet. Eller så kan man se det som fördröjd evaluering: man lägger hela uttrycket (utan att evaluera) på stacken, och kör igång med metoden. När (ifall) metoden behöver argumentet, och slår upp det i tabellen, evalueras den, och ersätts med värdet. Nästa gång ligger värdet i tabellen. 23
Skillnad på det som skickas Primitiv variabel (ex. int, double, boolean) Innehåller själva värdet Referens Adress till ställe i datorns minne Programmering tillämpningar och datastrukturer 24 Notera att tilldelning =, test == 24
int n String namn Referenser i Java 3F02E3A0 3F02E3A1 3F02E3A2 3F02E3A3 3F02E3A4 3F02E3A5 3F02E3A6 datorns RAM-minne 123 3F02E3A5 Kalle Programmering tillämpningar och datastrukturer 25 Referenser pekar på en adress. När en referens evalueras och skickas som argument, kommer metoden att få adressen. Kan alltså böka omkring med det som refereras till och åstadkomma förändringar som består även efter att anropet är avslutat. 25
Call-by-reference Evaluering ger kopia av referensen som argument Kommer att kunna förändra variabelvärde utanför metoden Programmering tillämpningar och datastrukturer 26 CBV blir i praktiken CBR i Java, eftersom det är en adress som skickas till metoden (när argumentet var en referens). Metoden får alltså en egen referens, men till samma objekt som anroparen håller i! 26
Primitiva variabler - referenser Primitiv variabel (ex. int, double, boolean) Innehåller själva värdet Referens Adress till ställe i datorns minne Programmering tillämpningar och datastrukturer 27 Notera att tilldelning =, test == OK, vad har den här skillnaden för konsekvenser? 27
Exempel String myname = Kalle ; backupmyname = myname; myname = Jens ; System.print(backupMyName); Jens Programmering tillämpningar och datastrukturer 28 28
Referens myname Kalle myname backupmyname Jens Programmering tillämpningar och datastrukturer 29 Vad som händer vid tilldelning är att en referens skapas. Vid nästa tilldelning ny referens till samma objekt! När sedan myname ändras till Jens kommer även backupmyname att referera till denna. Vill man alltså komma ihåg namnet måste man kopiera strängen/texten (Skansholms terminologi). 29
Lösning Kopiera strängen String myname = Kalle ; // vill ha nytt objekt, dvs. ny sträng backupmyname = String.copyValueOf(myName); myname = Jens ; System.print(backupMyName); Kalle Programmering tillämpningar och datastrukturer 30 Gäller alla objekt som man skapat. Vad man har är referenser till dem, variablerna/objektnamnen innehåller inte själva objekten (utan bara en adress till dem). 30
Inbyggda primitiva datatyper Numeriska typer: int, float, double, boolean char true eller false (OBS! ej 0 1) String mystring = Kalle ; Klass som kan instansieras utan new mystring refererar till nytt objekt (instans av klassen String) Programmering tillämpningar och datastrukturer 31 Stor bokstav i String markerar att det är fråga om en klass, dvs. att mystring är en referens till en instans av denna klass. 31
Strängar Strängar kan inte ändras sedan de skapats Vid varje ändring slängs gamla strängen och nytt skapas Om många ändringar, bättre att använda StringBuffer Programmering tillämpningar och datastrukturer 32 32
StringBuffer StringBuffer sb = new StringBuffer( Hej hej ); Objektets innehåll kan ändras sb.append(" Kalle!"); sb.insert(7, ","); // lägg in på pos 7 sb.replace(4, 7, "då"); // ersätt bokst 4 till 7 System.out.println(sb); Hej då, Kalle! Obs! första pos = 0 Programmering tillämpningar och datastrukturer 33 Defaultkapacitet 16 tecken (denna utökas med det antal tecken man använt vid initieringen; i vårt exempel (första raden kod) ger detta 23 teckens kapacitet). 33
Operationer på strängar Konkatenering: String s = Mitt namn är + namn; Om namn inte är av typen sträng anropas namn.tostring() automatiskt Om inte definierad: letar efter tostring() uppåt i klasshierarkin Programmering tillämpningar och datastrukturer 34 34
Operationer på strängar Viktigt att tostring() är definierad i klassen I så fall ger: System.out.println(mittObjekt); en snygg utskrift av objektets tillstånd Annars kan man få @374303481556 vid utskrift! Programmering tillämpningar och datastrukturer 35 Som default körs Object.toString(); (om inte definierat längre ner i klasshierarkin). 35
Operationer på strängar Sökning efter delsträng: int index = s.indexof( är, 0); // söksträng, startindex Plocka ut en delsträng: s.substring(0, s.length-1); // startindex, stopindex Programmering tillämpningar och datastrukturer 36 36
Operationer på strängar Escape-tecken ( kommandotecken ) \n = ny rad (Unix) \n\r = ny rad (Windows text-filer) \t = tab s = namn + \t + ålder + \n ; Konvertering till/från tal int x = Integer.parseInt(s); String s = Integer.toString(42); Programmering tillämpningar och datastrukturer 37 37
s1 == s2 Jämföra strängar Jämför två pekare! Inte vad vi vill ha! I stället: s1.equals(s2); s1.equalsignorecase(s2); Sortera strängar: s1.compareto(s2) 0-1 1 om lika om s1 < s2 om s1 > s2 Programmering tillämpningar och datastrukturer 38 38
package lab2; import java.util.*; /** * * @author Rita Kovordányi */ public class MyList { } Namn på mitt paket Vill komma åt alla klasser i detta paket Programmering tillämpningar och datastrukturer 39 Anger man inget eget paket hamnar klasserna i default-paketet. Kan bli mycket rörigt där. Man kanske har lekt omkring med listor och har glömt allt det där, och någon månad senare vill programmera listor på allvar. Det kan bli namnkrockar, och en massa strul Bättre att skapa nytt paket för alla små idéer man vill testa. Importerar alla klasser i paketet java.util. 39
Vill ibland slippa skriva Math vid varje anrop Math.random(); package MyPackage; import static java.util.math.*; Nu kan man skriva klassnamn istf paketnamn sqrt(3.14); // istf Math.sqrt(3.14); Programmering tillämpningar och datastrukturer 40 Importerar alla klassmetoder i klassen Math. 40
Användbara paket java.lang själva språket (importeras automatiskt) java.util datastrukturer, matematiska fn:er javax.swing fönsterhantering java.io in- och utmatning med strömmar java.awt äldre fönsterhantering med grafik java.awt.event inmatning i fönster java.net nätverkskommunikation Programmering tillämpningar och datastrukturer 41 Vanliga paket i klassbiblioteket. 41