27.07.2013 Views

overlæsning, klassefelter og -metoder (static), konstante felter

overlæsning, klassefelter og -metoder (static), konstante felter

overlæsning, klassefelter og -metoder (static), konstante felter

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Pr<strong>og</strong>rammering 2004<br />

Forelæsning 3, tirsdag 14. september 2004<br />

• Indkapsling <strong>og</strong> synlighed<br />

• Overlæsning<br />

• Klasse<strong>felter</strong> <strong>og</strong> -<strong>metoder</strong><br />

• Konstante <strong>felter</strong><br />

• Betingede ordrer: if-else, if<br />

• Indlejrede betingede ordrer<br />

• Blokke<br />

• L<strong>og</strong>iske udtryk<br />

• Semikoloner. . .<br />

• Indrykning<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-1<br />

Klassen Time fra sidste forelæsning<br />

public class Time {<br />

private int hours, min; // since midnight<br />

public Time(int hours, int min) {<br />

this.hours = hours; this.min = min;<br />

}<br />

public String twoDigits(int n) { // used in toString<br />

return "" + (n / 10) + (n % 10);<br />

}<br />

public String toString() {<br />

return twoDigits(hours) + "." + twoDigits(min);<br />

}<br />

public Time plus(int m) { // return new Time m minutes later<br />

int totalmin = 60 * hours + min + m;<br />

return new Time(totalmin / 60, totalmin % 60);<br />

}<br />

public int to(Time t) { // return number of minutes to t<br />

return 60 * t.hours + t.min - 60 * hours - min;<br />

}<br />

public void move(int m) { // move time by m minutes<br />

int totalmin = 60 * hours + min + m;<br />

hours = totalmin / 60; min = totalmin % 60;<br />

}<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-2<br />

Indkapsling <strong>og</strong> synlighed: private <strong>felter</strong> <strong>og</strong> <strong>metoder</strong><br />

Felter der erklæres private kan kun ses <strong>og</strong> ændres inde i klassen:<br />

class Time {<br />

private int hours, min;<br />

...<br />

}<br />

De kan ikke læses eller ændres af <strong>metoder</strong> der hører til andre klasser.<br />

God (objektorienteret) pr<strong>og</strong>rammeringsskik:<br />

• Lav alle <strong>felter</strong> private<br />

• Hvis et felt skal kunne aflæses udefra, så definér en public get-metode for feltet:<br />

public int getHours() {<br />

return hours;<br />

}<br />

Så skal brugere af Time-klassen skrive t1.getHours() i stedet for t1.hours<br />

Metoder kan <strong>og</strong>så erklæres private i stedet for public, hvis de kun skal kunne bruges i klassen selv.<br />

Opgave: Bør twoDigits være private?<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-3<br />

Hvorfor gøre livet besværligt for andre klasser?<br />

• For at sikre dataintegritet i Time-klassen:<br />

Det er f.eks. ønskeligt at konstruktorer <strong>og</strong> <strong>metoder</strong> i Time sikrer at 0 ≤ min ≤ 59.<br />

Men så kan vi jo ikke tillade udefrakommende at udføre eksempelvis t1.min = 62.<br />

Altså må andre klasser ikke få adgang til feltet min.<br />

• For at sikre at man kan skifte datarepræsentation i Time-klassen:<br />

Vi kunne ombestemme os <strong>og</strong> repræsentere et tidspunkt som antal minutter siden midnat:<br />

class Time {<br />

int min; // Since midnight<br />

...<br />

}<br />

Det ville faktisk gøre de fleste <strong>metoder</strong> i Time simplere.<br />

Men hvis der stod t1.hours alle mulige andre steder i pr<strong>og</strong>rammet, skulle det rettes alle de steder.<br />

Hvis der står t1.getHours() i stedet, så skal vi kun rette ét sted, i Time-klassen:<br />

public int getHours() {<br />

return min / 60;<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-4


Overlæsning af konstruktorer <strong>og</strong> <strong>metoder</strong><br />

En konstruktor er karakteriseret ved sin signatur.<br />

Signaturen er konstruktorens navn (som er klassens navn) samt typerne af dens formelle parametre.<br />

Eksempel: Signaturen for konstruktoren Time fra før er ‘Time(int, int)’.<br />

En klasse kan have flere konstruktorer (som jo har samme navn) så længe deres signaturer er forskellige.<br />

Dette kaldes <strong>overlæsning</strong> af konstruktoren. På engelsk: ‘overloading’.<br />

Metoder kan overlæsses lige som konstruktorer.<br />

D.v.s. at der kan være flere <strong>metoder</strong> med samme navn men forskellige signaturer i en klasse.<br />

En metodes signatur er dens navn samt typerne af dens formelle parametre.<br />

Metodens resultat-type indgår ikke i signaturen.<br />

Overlæssede <strong>metoder</strong> med samme navn kan have forskellige resultat-typer.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-5<br />

Eksempel: Overlæsning af konstruktorer i Time<br />

public class Time {<br />

private int hours, min; // since midnight<br />

}<br />

public Time(int hours, int min) {<br />

this.hours = hours;<br />

this.min = min;<br />

}<br />

public Time(int hours) {<br />

this.hours = hours;<br />

this.min = 0;<br />

}<br />

public Time(Time t) {<br />

this.hours = t.hours;<br />

this.min = t.min;<br />

}<br />

... <strong>metoder</strong> uændrede ...<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-6<br />

Test af ny Time klasse<br />

public class TestTime2 {<br />

}<br />

public <strong>static</strong> void main(String[] args) {<br />

Time t0, t1, t2, t3;<br />

t0 = new Time(12);<br />

t1 = new Time(12, 35); // A<br />

System.out.println("t0 = " + t0);<br />

System.out.println("t1 = " + t1);<br />

}<br />

t2 = t1.plus(40);<br />

t3 = new Time(t1);<br />

t1.move(45); // B<br />

System.out.println("t1 = " + t1);<br />

System.out.println("t2 = " + t2);<br />

System.out.println("t3 = " + t3);<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-7<br />

Datamatens hukommelse ved kørsel af TestTime2<br />

A<br />

t0 t1 t2 t3<br />

: Time<br />

hours 12<br />

min 0<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

B t0 t1 t2 t3<br />

: Time<br />

hours 12<br />

min 0<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

hours<br />

min<br />

: Time<br />

hours 12<br />

min 35<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

: Time<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

: Time<br />

12 13 hours 13<br />

35 20 min 15<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

: Time<br />

hours 12<br />

min 35<br />

twoDigits<br />

toString<br />

plus<br />

to<br />

move<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-8


Overlæsning af konstruktorer, this()<br />

Det er muligt fra en konstruktor at kalde en anden af klassens konstruktorer.<br />

Den anden konstruktor kaldes med det specielle metodekald<br />

this( argumenter )<br />

Alternativ udgave af konstruktorerne i Time:<br />

public class Time {<br />

private int hours, min; // since midnight<br />

}<br />

public Time(int hours, int min) {<br />

this.hours = hours;<br />

this.min = min;<br />

}<br />

public Time(int hours) {<br />

this(hours,0);<br />

}<br />

public Time(Time t) {<br />

this(t.hours,t.min);<br />

}<br />

... <strong>metoder</strong> uændrede ...<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-9<br />

Klasse<strong>felter</strong> <strong>og</strong> -<strong>metoder</strong>: <strong>static</strong><br />

Felter kan erklæres som fælles for klassen frem for tilhørende hvert objekt.<br />

Fælles <strong>klasse<strong>felter</strong></strong> erklæres med nøgleordet <strong>static</strong>.<br />

<strong>static</strong> standard<br />

Antal kopier Én fælles Én for hvert objekt<br />

Fælles for klasse Ja Nej<br />

Tilsvarende kan en metode erklæres <strong>static</strong> hvis den ikke afhænger af et objekts <strong>felter</strong>.<br />

Eksempel 1: main metoden i pr<strong>og</strong>rammer er <strong>static</strong>, den kaldes uden at der skabes et objekt af dens klasse.<br />

Eksempel 2: Metoden twoDigits i Time klassen kunne være <strong>static</strong>.<br />

Konstante <strong>felter</strong>: final<br />

Med nøgleordet final kan man erklære at et felt ikke må ændres.<br />

final standard<br />

Kan ændres Nej Ja<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-10<br />

Eksempel: Person med entydigt løbenummer (TaltPerson)<br />

public class TaltPerson {<br />

private String fornavne;<br />

private String efternavn;<br />

public final int nummer; // Løbenummer<br />

}<br />

// Tæl hvor mange personer, der er oprettet<br />

private <strong>static</strong> int antalPersoner = 0;<br />

public <strong>static</strong> int getAntalPersoner() {<br />

return antalPersoner;<br />

}<br />

public TaltPerson(String f, String e) {<br />

fornavne = f;<br />

efternavn = e;<br />

antalPersoner = antalPersoner + 1;<br />

nummer = antalPersoner;<br />

}<br />

// ... Øvrige <strong>metoder</strong> som i Person klassen<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-11<br />

Test af TaltPerson<br />

public class TestTaltPerson {<br />

public <strong>static</strong> void main(String [] args) {<br />

TaltPerson georg = new TaltPerson("Georg","Brandes");<br />

TaltPerson tove = new TaltPerson("Tove","Ditlevsen");<br />

TaltPerson dan = new TaltPerson("Dan","Turell");<br />

}<br />

}<br />

System.out.println("Der er oprettet " + TaltPerson.getAntalPersoner() +<br />

" personer");<br />

System.out.println(tove + " er nummer " + tove.nummer);<br />

// tove.nummer = 5; // ulovligt, nummer er final<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-12


Datamatens hukommelse ved kørsel af TestTaltPerson<br />

Class TaltPerson<br />

antalPersoner 0 1<br />

2 3<br />

getAntalPersoner<br />

: TaltPerson<br />

fornavne<br />

efternavn<br />

nummer 1<br />

setFornavne<br />

setEfternavn<br />

getFornavne<br />

getEfternavn<br />

toString<br />

: TaltPerson<br />

fornavne<br />

efternavn<br />

nummer 3<br />

setFornavne<br />

setEfternavn<br />

getFornavne<br />

getEfternavn<br />

toString<br />

: String<br />

"Georg"<br />

: String<br />

"Brandes"<br />

: String<br />

"Dan"<br />

: String<br />

"Turell"<br />

georg<br />

dan<br />

: TaltPerson<br />

fornavne<br />

efternavn<br />

nummer 2<br />

setFornavne<br />

setEfternavn<br />

getFornavne<br />

getEfternavn<br />

toString<br />

: String<br />

"Tove"<br />

: String<br />

tove<br />

"Ditlevsen"<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-13<br />

Betingede ordrer: if-else<br />

Pr<strong>og</strong>rammer skal kunne vælge mellem forskellige alternativer.<br />

Generelt format for if-else ordre:<br />

if (udtryk)<br />

ordre1<br />

else<br />

ordre2<br />

Betingelsen udtryk skal have en værdi af typen boolean, dvs.true eller false.<br />

Virkning:<br />

1. Beregn værdien af udtryk,<br />

2. hvis true så udfør ordre1, ellers udfør ordre2.<br />

Dvs. at if-else vælger mellem to ordrer, afhængigt af udtryk.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-14<br />

Eksempel med if-else:<br />

En klasse til at repræsentere karakterer efter 13-skalaen:<br />

public class Karakter {<br />

public final int tal; // karakterens talværdi, 0 til 13<br />

}<br />

public Karakter(int tal) {<br />

this.tal=tal;<br />

}<br />

public String toString() {<br />

if (tal < 5)<br />

return "0" + tal;<br />

else<br />

return "" + tal;<br />

}<br />

public boolean erBestaaet() {<br />

return tal >= 6;<br />

}<br />

public String resultat() {<br />

if ( erBestaaet() )<br />

return "bestået";<br />

else<br />

return "dumpet";<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-15<br />

Brug af Karakter klassen:<br />

public class TestKarakter1 {<br />

}<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

public <strong>static</strong> void main(String [] args) {<br />

udskrivResultat( new Karakter(5) );<br />

udskrivResultat( new Karakter(6) );<br />

udskrivResultat( new Karakter(10) );<br />

udskrivResultat( new Karakter(3) );<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-16


Betingede ordrer, if<br />

public class TestKarakter2 {<br />

}<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

if ( k.erBestaaet() )<br />

System.out.print("Hurra! ");<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

public <strong>static</strong> void main(String [] args) {<br />

// ... samme som før<br />

}<br />

Generelt format:<br />

if (udtryk)<br />

ordre1<br />

Virkning:<br />

1. Beregn værdien af udtryk,<br />

2. hvis true udfør ordre1.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-17<br />

En almindelig fejl<br />

Opgave: Hvad ville der ske hvis udskrivResultat i stedet var skrevet som neden for?<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

if ( k.erBestaaet() );<br />

System.out.print("Hurra! ");<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-18<br />

En blok består af flere ordrer<br />

En række ordrer kan grupperes til én ordre med { ... }:<br />

En blok kan forekomme hvor som helst en ordre kan forekomme.<br />

public class TestKarakter3 {<br />

<strong>static</strong> int antalBestaaet = 0;<br />

}<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

if ( k.erBestaaet() ) {<br />

System.out.print("Hurra! ");<br />

antalBestaaet = antalBestaaet + 1;<br />

}<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

public <strong>static</strong> void main(String [] args) {<br />

udskrivResultat( new Karakter(5) );<br />

udskrivResultat( new Karakter(6) );<br />

udskrivResultat( new Karakter(10) );<br />

udskrivResultat( new Karakter(3) );<br />

System.out.println("Antal bestået: " + antalBestaaet);<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-19<br />

En anden almindelig fejl<br />

Opgave: Hvad ville der ske hvis udskrivResultat i stedet var skrevet som neden for?<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

if ( k.erBestaaet() )<br />

System.out.print("Hurra! ");<br />

antalBestaaet = antalBestaaet + 1;<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-20


else-problemet<br />

Hvad giver dette hvis x er 4:<br />

if (x > 5)<br />

if (y > 5)<br />

System.out.println("gren A");<br />

else<br />

System.out.println("gren B");<br />

Regel: En else-gren knytter sig til den seneste uafsluttede if.<br />

Man kan afslutte en if ved at lukke den inde i en blok:<br />

if (x > 5) {<br />

if (y > 5)<br />

System.out.println("gren A");<br />

} else<br />

System.out.println("gren B");<br />

Brug gerne ekstra { ... } til at gøre meningen med en ordre klar.<br />

Ligesom man bruger ekstra ( ... ) til at gøre meningen med et regneudtryk klar.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-21<br />

Sammenligningsoperatorer<br />

Operator Betydning Eksempel<br />

== Lig med x == 60<br />

!= Forskellig fra x != 60<br />

< Mindre end x < 60<br />

60<br />

>= Større end eller lig med x >= 60<br />

Bemærk: Sammenligningsoperatorerne virker kun for tal, ikke for tegnstrenge <strong>og</strong> andre objekter.<br />

Resultattypen er boolean, dvs.true eller false.<br />

Sammenligningsoperatorerne har alle samme præcedens <strong>og</strong> lavere præcedens (binder svagere) end de<br />

aritmetiske operatorer (regnearterne).<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-22<br />

L<strong>og</strong>iske operatorer<br />

L<strong>og</strong>iske operatorer i præcedensorden fra høj til lav præcedens:<br />

Operator Betydning Eksempel<br />

! Ikke (Negation) !(x == 60)<br />

&& Og (Konjunktion) 0 = 60<br />

Argumenttyperne er boolean <strong>og</strong> resultattypen er boolean.<br />

! har højere præcedens (binder stærkere) end sammenlignings- <strong>og</strong> aritmetiske operatorer mens && <strong>og</strong> || har<br />

lavere præcedens (binder svagere) end sammenligningsoperatorerne.<br />

Udtrykket udregnes fra venstre mod højre.<br />

Hvis udtryk1 er falsk i udtryk1 && udtryk2 så udregnes udtryk2 ikke.<br />

Hvis udtryk1 er sandt i udtryk1 || udtryk2 så udregnes udtryk2 ikke.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-23<br />

Små opgaver i l<strong>og</strong>iske udtryk<br />

Heltallet m er mindst 1 <strong>og</strong> højst 12.<br />

Tallet h er større end eller lig med nul, <strong>og</strong> mindre end 24.<br />

x i anden er mindre end 25.<br />

y er mindre end 40 eller større end 100<br />

aar er delelig med 4.<br />

aar er ikke delelig med 100.<br />

aar er delelig med 400.<br />

aar er et skudår: delelig med 4 men ikke med 100, eller delelig med 400.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-24


Hvor skal der semikolon?<br />

• Intet semikolon efter if (men muligvis efter grenene).<br />

• Put semikolon efter en ordre lavet af et udtryk: tildeling, metodekald, osv.<br />

• Put semikolon efter en return ordre.<br />

• Put semikolon efter variabel-erklæringer.<br />

• Der skal ikke semikolon efter en blok { ... }.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-25<br />

Hvor skal der semikolon(er):<br />

if (x != 0) {<br />

sum = sum + 1.0/x<br />

antal = antal + 1<br />

}<br />

Hvor skal der semikolon(er):<br />

if (x != 0)<br />

sum = sum + 1.0/x<br />

else<br />

sum = 0<br />

Hvor skal der semikolon(er):<br />

if (x != 0)<br />

sum = sum + 1.0/x<br />

else<br />

{ sum = 0 }<br />

Hvor skal der semikolon(er):<br />

if (x != 0)<br />

sum = sum + 1.0/x<br />

else<br />

if (y != 0)<br />

sum = sum + 1.0/y<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-26<br />

Pr<strong>og</strong>ramlayout, indrykning<br />

Indrykning har ikke n<strong>og</strong>en betydning for datamaskinen.<br />

Men for mennesker er det meget nemmere at læse<br />

<strong>static</strong> void udskrivResultat(Karakter k) {<br />

if ( k.erBestaaet() ) {<br />

System.out.print("Hurra! ");<br />

antalBestaaet = antalBestaaet + 1;<br />

}<br />

System.out.println("Med " + k + " er man " + k.resultat());<br />

}<br />

end at læse<br />

<strong>static</strong> void udskrivResultat(Karakter k) { if ( k.erBestaaet() ) {<br />

System.out.print("Hurra! "); antalBestaaet = antalBestaaet + 1;<br />

} System.out.println("Med " + k + " er man " + k.resultat()); }<br />

Datamaskinen er ligeglad, men det er jeres lærer ikke. . .<br />

Indryk altid underordnede linier (grenene i en if, ordrer i en blok, indmaden i <strong>metoder</strong>, ...)<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-27<br />

Nyt idag<br />

• Synlighed: private <strong>og</strong> public<br />

• Overlæsning<br />

• Klasse<strong>felter</strong> <strong>og</strong> -<strong>metoder</strong> (<strong>static</strong>)<br />

• Konstante <strong>felter</strong> (final)<br />

• Betingede sætninger: if-else, if<br />

• Blokke<br />

• L<strong>og</strong>iske udtryk<br />

Læsning for idag: Morelli,<br />

kapitel 3 t.o.m. s. 147, undt. 3.6.5,<br />

kapitel 5 t.o.m. s. 259 midt, undt. 5.6.6.<br />

Pr<strong>og</strong>rammering 2004 KVL Side 3-28

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!