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