Introduktion till Java (del1) 1 Översikt Att köra Java Kompilator – Interpretator – Statisk vs. dynamisk variabelbindning Parameter-passing Primitiva datatyper – Strängar Paket Programmering — tillämpningar och datastrukturer 2 2 Köra Java Bindning Köra Java >> javac MyCode.java Producerar MyCode.class – ”Assemblerkod” för JVM – Par.passing Datatyper >> java MyCode – Interpreteras Paket Programmering — tillämpningar och datastrukturer 3 3 Köra Java Bindning Program i Java Object Filstruktur i NetBeans Fågel Rovfågel Par.passing Datatyper Pingvin Duva Falk Varje klassdefinition i egen fil Biblioteksfiler (paket) Paket Programmering — tillämpningar och datastrukturer 4 Man ska ha kompilerat alla ingående filer, och lagt .class-filerna tillsammans. 4 Köra Java Kompilering Bindning källkod Par.passing Hello.java kompilator Datatyper Hello.class Javabytekod Paket Programmering — tillämpningar och datastrukturer 5 5 Köra Java Att köra program Bindning filsystem Par.passing Datatyper RAM cache förinladdning av material som snart kommer att behövas Paket CPU 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 Köra Java JVM Hello.class Bindning Par.passing Unix Windows Darwin RAM RAM RAM Datatyper CPU CPU CPU Paket 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 Köra Java Bindning Mjukvarudator Java Virtual Machine (JVM) – Interpreterar Java-program (.class) – Par.passing Datatyper Implementeras olika på olika plattformar Interpretering mot dator Olika för olika plattformar – Unix, Mac, PC – Paket Finns aldrig några exe-filer Eg. operativsystemsberoende Solaris, Darwin, Windows Programmering — tillämpningar och datastrukturer 8 8 Köra Java Bindning I två steg Kompilering av källkod (.java) – Par.passing Datatyper Build (flera filer som ska kopplas in) Producerar bytecode (.class) ® Gör språket Java plattformsoberoende! ® Möjliggör dynamisk bindning Paket 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 Köra Java Bindning Varför interpreterat? Polymorfism – dvs. samma namn på metod i superklass och subklass – Par.passing Datatyper Ex.vis. i kod för grafik där paint omdefinieras ofta i subklass Objekt skapas ”on-the-fly” under körning Paket 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 Köra Java Variabelbindning Bindning Par.passing Datatyper Två sätt Bestäms av syntaktiska strukturen hos koden – Bestäms av kontrollstrukturen (exekveringsflödet ) – Paket 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. Bindningen 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 Köra Java Bindning Variabelbindning (Lisp) (let ((n 1)) (defun addn (z) (add n z))) detta n eftersom definitionen sitter i den här omgivningen Par.passing (let ((n 2)) (addn 3)) Datatyper Paket detta n eftersom anropet sker i den här kontexten Statisk bidning → 4 Dynamisk bindning → 5 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 Köra Java Bindning Statisk bindning Variabelns värde bestäms av dess position i programmet – Par.passing Datatyper Närmast omslutande programblock där variabeln är deklarerad → Kompilatorn kan bestämma variabelinstans och lägga in i exe-filen Paket 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 Köra Java Bindning Par.passing Datatyper 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 Paket 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 Köra Java Bindning Par.passing Common Lisp Använder statisk bindning Fria variabler binds vid definitionstillfället Alla omgivningsvariabler skickas med när funktionen skickas som argument Datatyper Paket 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 Köra Java Bindning Java Använder dynamisk bindning Därför körs JVM interpreterat Plussidan: flexibilitet – Nackdel: långsam – Par.passing Datatyper Just-in-time kompilering ger något förbättrad prestanda Paket 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 Köra Java Bindning Par.passing Parametrar – argument public static int add(int a, int b) { … } Argument (aktuell parameter) vid anrop Math.add(3,4) Datatyper Paket Parameter (formell parameter) vid definition 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 Köra Java Bindning Anropssätt Call-by-value Enkel – Argumenten evalueras en gång – Par.passing Call-by-name – Oändliga loopar Odefinierade operationer (delning med 0) Datatyper – Paket Kan undvika vissa beräkningar Ger ren semantik – programkorrekthet Call-by-need Programmering — tillämpningar och datastrukturer 19 Call-by-value vida använt, lätt att implementera. 19 Köra Java Call-by-value Bindning misse.sättÅlder(ålder); Par.passing Datatyper Steg1: Evaluera ålder – Steg2: Lägg värdet på anropsstacken – Steg3: Lämna kontrollen till metoden (tillsammans med en pekare till stacken) – Paket Programmering — tillämpningar och datastrukturer 20 20 Köra Java Call-by-name Bindning Steg1: Ersätta parameter på alla platser i metod-kroppen med motsvarande argument Par.passing Steg2: Starta exekvera metoden Steg3: Evaluera argument vid behov Argument kan komma att evalueras flera gånger Oftast onödig extra-beräkning Datatyper Paket 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 Köra Java Bindning Skillnad CBV – CBN public static void slask(int element, boolean b) { if (b) { System.out.println("Allt är ok"); } else { Par.passing System.out.println(element); } } Datatyper public static void main(String[] args) { int[] poäng = new int[10]; Paket 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 Köra Java Bindning Par.passing Datatyper Call-by-need Lat evaluering Fördröjd evaluering tills argumentet faktiskt används i metoden Evalueras en gång Kombinerar fördelarna med CBV och CBN Paket 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 Köra Java Skillnad på det som skickas Bindning Primitiv variabel (ex. int, double, boolean) – Par.passing Innehåller själva värdet Referens – Adress till ställe i datorns minne Datatyper Paket Programmering — tillämpningar och datastrukturer 24 Notera att tilldelning =, test == 24 Köra Java Referenser i Java datorns RAM-minne Bindning int n Par.passing Datatyper String namn 3F02E3A0 3F02E3A1 123 3F02E3A2 3F02E3A5 3F02E3A3 3F02E3A4 3F02E3A5 Paket Kalle 3F02E3A6 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 Köra Java Call-by-reference Bindning Par.passing Evaluering ger kopia av referensen som argument Kommer att kunna förändra variabelvärde utanför metoden Datatyper Paket 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 Köra Java Primitiva variabler - referenser Bindning Primitiv variabel (ex. int, double, boolean) – Par.passing Innehåller själva värdet Referens – Adress till ställe i datorns minne Datatyper Paket Programmering — tillämpningar och datastrukturer 27 Notera att tilldelning =, test == OK, vad har den här skillnaden för konsekvenser? 27 Köra Java Exempel Bindning Par.passing String myName = ”Kalle”; backupMyName = myName; myName = ”Jens”; System.print(backupMyName); → Jens Datatyper Paket Programmering — tillämpningar och datastrukturer 28 28 Köra Java Bindning Referens myName Kalle myName Jens Par.passing Datatyper backupMyName Paket 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 Köra Java Bindning Lösning Kopiera strängen String myName = ”Kalle”; Par.passing // vill ha nytt objekt, dvs. ny sträng backupMyName = String.copyValueOf(myName); myName = ”Jens”; Datatyper System.print(backupMyName); → Kalle Paket 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 Köra Java Bindning Inbyggda primitiva datatyper Numeriska typer: int, float, double, … boolean – Par.passing Datatyper Paket true eller false (OBS! ej 0 1) char SString 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 Köra Java Bindning Par.passing Datatyper 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 Paket Programmering — tillämpningar och datastrukturer 32 32 Köra Java Bindning StringBuffer StringBuffer sb = new StringBuffer(”Hej hej”); Par.passing 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 Datatyper Paket 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 Köra Java Bindning Operationer på strängar Konkatenering: String s = ”Mitt namn är ” + namn; Par.passing Datatyper Om namn inte är av typen sträng anropas namn.toString() automatiskt – Om inte definierad: letar efter toString() uppåt i klasshierarkin – Paket Programmering — tillämpningar och datastrukturer 34 34 Köra Java Bindning 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! – Par.passing Datatyper Paket Programmering — tillämpningar och datastrukturer 35 Som default körs Object.toString(); (om inte definierat längre ner i klasshierarkin). 35 Köra Java Bindning Operationer på strängar Sökning efter delsträng: int index = s.indexOf(”är”, 0); // söksträng, startindex Par.passing Datatyper Plocka ut en delsträng: s.subString(0, s.length-1); // startindex, stopindex Paket Programmering — tillämpningar och datastrukturer 36 36 Köra Java Bindning Operationer på strängar Escape-tecken (”kommandotecken”) \n = ny rad (Unix) \n\r = ny rad (Windows text-filer) Par.passing \t = tab s = namn + ”\t” + ålder + ”\n”; Datatyper Paket Konvertering till/från tal int x = Integer.parseInt(s); String s = Integer.toString(42); Programmering — tillämpningar och datastrukturer 37 37 Köra Java Jämföra strängar s1 == s2 Bindning Par.passing Datatyper Paket 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 Programmering — tillämpningar och datastrukturer om lika om s1 < s2 om s1 > s2 38 38 Köra Java Bindning Par.passing Datatyper Paket Paket package lab2; import java.util.*; /** * * @author Rita Kovordányi */ public class MyList { … } Programmering — tillämpningar och datastrukturer Namn på mitt paket Vill komma åt alla klasser i detta paket 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 Köra Java Bindning Paket Vill ibland slippa skriva Math vid varje anrop – Math.random(); Par.passing package MyPackage; import static java.util.Math.*; klassnamn istf paketnamn Datatyper Paket Nu kan man skriva – sqrt(3.14); // istf Math.sqrt(3.14); Programmering — tillämpningar och datastrukturer 40 Importerar alla klassmetoder i klassen Math. 40 Köra Java Bindning Par.passing Datatyper 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 Paket Programmering — tillämpningar och datastrukturer 41 Vanliga paket i klassbiblioteket. 41