Programmering 1999 Forelæsning 4, fredag 10. september 1999 Klasser og objekter Felter, konstruktorer, this Eksempler på klasser: Time, Appointment Eksempler på metoder i Time og Appointment Klassefelter: static Konstante felter: final Indkapsling og synlighed: private og public Klassen Random: pseudo-tilfældige tal Programmering 1999 KVL Side 4-1 Klasser og objekter Uformelt En klasse repræsenterer et begreb: tidspunkt, aftale, bil, ko, person,... Et objekt repræsenterer en ting, en instans af et begreb: et bestemt tidspunkt, en bestemt bil, en bestemt ko, en bestemt person,... En klasse kan betragtes som en skabelon til et objekt. I programmeringssproget Java En klasse er en type, svarende til int, double, boolean, String,... Et objekt er en værdi, ligesom 17, 18.01, false, "abcdefg",... Faktisk er String en (indbygget) klasse. Faktisk skal alt i Java defineres inden i en klasse, jævnfør Hello.java. Undertiden bruges en klasse ikke til at repræsentere et begreb, men simpelthen til at samle noget programkode. Programmering 1999 KVL Side 4-2 Hvordan definerer man sine egne klasser Eksempel: Et tidspunkt på dagen kan beskrives som timer og minutter siden midnat: Et objekt af klasse Time har felter (eller variable) kaldet hours og min. Sådan erklærer man en variabel af type Time: Time t1; // Erklær variabel af type Time Sådan kunne man skabe og bruge objekter fra klassen Time: class Time1 { Time t1; t1 = new Time(); t1.hours = 12; t1.min = 35; Prik-notationen t1.hours betyder: feltet hours i det objekt som t1 henviser til. Felterne hours og min oprettes automatisk med værdien 0. Programmering 1999 KVL Side 4-3 Hvad er en variabel af type Time? Variablen t1 af type Time indeholder ikke et objekt fra klassen Time. Den indeholder en reference til et objekt fra klassen Time. Referencen i t1 kan være den specielle værdi null. I dette tilfælde henviser t1 ikke til noget objekt. Hvis referencen ikke er null, så skal den henvise til et objekt fra klassen Time. Programmering 1999 KVL Side 4-4
Konstruktorer En konstruktor bruges til at lave et objekt hørende til en klasse. En konstruktor, f.eks. Time(), har samme navn som klassen. Man kan definere konstruktorer for at kombinere oprettelse og initialisering: Time(int hh, int mm) { hours = hh; min = mm; Så kan vi lave Time-objekter direkte ved at skrive Time t1; t1 = new Time(12, 35); Time t2 = new Time(14, 0); En klasse uden konstruktorer er født med en default-konstruktor uden parametre: Time() { Et objekts felter oprettes med værdien 0 eller false eller null, afhængig af feltets type. Programmering 1999 KVL Side 4-5 Parametre kan skygge for felter Hvad hvis vi havde skrevet { hours = hours; min = min; Duer ikke, for hours i konstruktoren henviser til konstruktorens parameter, ikke feltet hours. Parametrene hours og min skygger for felterne hours og min. Der bliver altså ikke gemt noget i felterne hours og min. Referencen this For at betegne objektets felter kan man bruge præfikset this: { this.hours = hours; this.min = min; Inde i et objekt betyder this dette objekt, så this.hours betyder dette objekts hours-felt. Programmering 1999 KVL Side 4-6 Klassen Time: metoder Felter i objektet indeholder objektets tilstand. Metoder i objektet giver mulighed for at ændre tilstanden, eller kigge på tilstanden. // since midnight { this.hours = hours; this.min = min; String twodigits(int n) { return "" + (n / 10) + (n % 10); public String tostring() { return twodigits(hours) + "." + twodigits(min); Time plus(int min) { int totalmin = 60 * this.hours + this.min + min; return new Time(totalmin / 60, totalmin % 60); int to(time t) { return 60 * t.hours + t.min - 60 * hours - min; boolean before(time t) { return hours < t.hours hours == t.hours && min <= t.min; Programmering 1999 KVL Side 4-7 Eksempel på brug af Time-objekter public class Time2 { Time t1, t2; t1 = new Time(12, 35); t2 = t1.plus(40); System.out.println("t1 er " + t1); System.out.println("t2 er " + t2); System.out.println("t1 plus 10 min plus 50 min er " + t1.plus(10).plus(50)); System.out.println("t1 før t2 er " + t1.before(t2)); System.out.println("fra t1 til t2 er der " + t1.to(t2) + " minutter"); System.out.println("t1 er stadig " + t1); Udtrykket ("t1 er " + t1) betyder ("t1 er " + t1.tostring()) Prik-notationen t1.plus(10) betyder: kald metoden plus i det objekt som t1 henviser til. Programmering 1999 KVL Side 4-8
Nyt objekt eller ændret objekt Bemærk at t1.plus(10) laver et nyt Time-objekt. Der ændres ikke på t1. En metode kan sagtens ændre på selve objektet. Den skal bare ændre objektets felter i stedet for at kalde new Time() Opgave: Definér en metode void flyt(int min) som flytter et tidspunkt i stedet for at lave et nyt. Lav en for-løkke der udskriver alle klokkeslet fra 00.00 til 23.59 (der er 1440 minutter på et døgn). Programmering 1999 KVL Side 4-9 Klassen Appointment En aftale (Appointment) har et starttidspunkt, et sluttidspunkt, og en tekst: class Appointment { Time starttime, endtime; String text; Appointment(Time starttime, Time endtime, String text) { this.starttime = starttime; this.endtime = endtime; this.text = text; void prolong(int min) { endtime = endtime.plus(min); public String tostring() { return "fra " + starttime + " til " + endtime + ": " + text; Et Appointment-objekt indeholder to henvisninger til Time-objekter. Metoden tostring i Appointment udnytter implicit tostring fra Time. Felterne starttime og endtime konverterer sig selv til tegnstrenge. Programmering 1999 KVL Side 4-10 Brug af klassen Appointment class Appointment2 { Time kl1 = new Time(13, 0); Appointment task1, task2, task3; task1 = new Appointment(new Time(8, 0), new Time(9, 20), "forelæsning"); task2 = new Appointment(kl1, new Time(15,0), "bestyrelse"); task3 = new Appointment(kl1, new Time(15,0), "øvelser"); System.out.println("" + task1); System.out.println("" + task2); System.out.println("" + task3); task3.prolong(120); System.out.println("" + task3); Objekterne task2 og task3 henviser til samme klokken 13 objekt, men to forskellige klokken 15 objekter. Programmering 1999 KVL Side 4-11 Fælles klassefelter: nøgleordet static Et klassefelt (eller en klassevariabel) er fælles for alle objekter i klassen. For eksempel kunne vi definere timezone (antal minutter øst for Greenwich) fælles for alle tidspunkter. En klassevariabel erklæres med nøgleordet static. static int timezone = 60; Programmering 1999 KVL Side 4-12
Konstante felter: nøgleordet final Undertiden ved vi at et felts værdi aldrig vil blive ændret: det er konstant. Desuden vil vi gerne sikre at resten af programmet ikke ændrer det ved en fejl. Det kan gøres med attributtet final. For eksempel kan man i klassen Time definere tidspunktet noon (middag) en gang for alle: final static Time noon = new Time(12, 0); Programmering 1999 KVL Side 4-13 Indkapsling: private felter og metoder Felter der erklæres private kan kun ses og ændres inde i klassen: private De kan ikke læses eller ændres af metoder der hører til andre klasser. God programmeringsskik i store programmer: Lav alle felter private Hvis et felt skal kunne aflæses udefra, så definér en get-metode: { return hours; Så skal brugere af Time-klassen skrive t1.gethours() i stedet for t1.hours Programmering 1999 KVL Side 4-14 Hvorfor gøre livet besværligt for andre klasser? For at sikre dataintegritet i Time-klassen: Det er ønskeligt at konstruktorer og metoder i Time sikrer at 0 min 59. Men så kan vi jo ikke tillade udefrakommende at udføre eksempelvis t1.min = 62. For at sikre at man kan skifte datarepræsentation i Time-klassen: Vi kunne ombestemme os og repræsentere et tidspunkt som antal minutter siden midnat: int min; // Since midnight (Det ville gøre nogle operationer nemmere). Men hvis der stod t1.hours alle mulige andre steder i programmet, skulle det rettes alle de steder. Hvis der står t1.gethours() i stedet, så skal vi kun rette ét sted, i Time-klassen: { return (min / 60); Programmering 1999 KVL Side 4-15 Time med private og public (filnavn Time2b.java) private // since midnight public final static Time noon = new Time(12, 0); public static int timezone = 60; public { this.hours = hours; this.min = min; { return hours; public int getmin() { return min; private static String twodigits(int n) { return "" + (n / 10) + (n % 10); public String tostring() { public Time plus(int min) { public int to(time t) { public boolean before(time t) { Metoden twodigits er private (lokal i klassen); og static (afhænger ikke af felterne). Programmering 1999 KVL Side 4-16
for hvilket Programmering 1999 KVL Side 4-18 Metoden Math.random() virker som r.nextdouble(), for en indbygget generator. Metoden r.nextint() givet et ligefordelt tilfældigt heltal. Metoden r.nextdouble() givet et ligefordelt tilfældigt. Dette er nyttigt når man skal finde fejl i programmer, fordi resultaterne er reproducerbare. Ud fra et givet frø vil generatoren altid lave den samme sekvens af tilfældige tal. Konstruktoren new Random() laver en generator med et frø taget fra datamatens indbyggede ur. Konstruktoren new Random(79891263152) laver en generator med frø 79891263152. Den indbyggede klasse Random Pseudo-tilfældige tal kan bruges til at simulere komplicerede (naturlige) processer. Men faktisk er hvert tal helt bestemt af det foregående. Det første tal kaldes sekvensens frø (engelsk: seed). En pseudo-tilfældig talfølge forekommer tilfældig: Pseudo-tilfældige tal Programmering 1999 KVL Side 4-17 Forklar public static void main(string[] args) (Der er mere at sige om synlighed når vi har lært om subklasser og pakker) Andre klasser Ja Ja Nej public standard private Synlighed: private og public Kan ændres Nej Ja final standard Konstante felter: final Fælles for klasse Ja Nej Antal kopier Én fælles Én for hvert objekt static standard elter Klassef og -metoder: static At bruge Random til at kaste terninger import java.util.random; public class Random1 { Random r = new Random(); for (int i=0; i < 10; i++) { int res = (int)(1 + 6 * r.nextdouble()); System.out.print(res + " "); System.out.println(); For at generere et tilfældigt heltal mellem 1 og 6 (inklusive), brug (int)(1 + 6 * r.nextdouble()) Brug ikke det der foreslås i Lewis og Loftus: 1 + r.nextint() % 6 Årsag: de nederste bit i et pseudo-tilfældigt tal er mindre tilfældige end de øverste. Programmering 1999 KVL Side 4-19 Læs Lewis og Loftus afsnit 4.1-4.8 og 5.2. En klasse (en type) repræsenterer et begreb Et objekt (en værdi) hørende til klassen repræsenterer en instans af begrebet En variabel af klassetype er enten null, eller henviser til et objekt Navnet this inde i et objekt henviser til objektet selv En klasse har konstruktorer (til at skabe objekter hørende til klassen) Et objekt har felter (til at indeholde objektets tilstand) Et objekt har metoder (til at operere på objektets tilstand) Synligheden af felter og metoder kan modificeres med public og private Klassefelter og klassemetoder (static) er fælles for alle klassens objekter Et konstant felt (final) kan ikke ændres efter initialiseringen En tilfældigtalsgenerator er et objekt af klasse Random Oversigt over Javas indbyggede klasser og metoder findes i bogens appendiks O (meget kortfattet); på nettet (naturligvis); se kursets webside Materialer på nettet... Programmering 1999 KVL Side 4-20