PowerPoint-presentatie

advertisement
HOOFDSTUK 8: OBJECT – BASED PROGRAMMEREN
1.
INLEIDING:
O.O. - concepten en O.O. - terminologie
De traditionele software-ontwikkeling = top-down-analyse
(= functionele decompositie) + gestructureerd
programmeren (Cobol, C, Pascal,…)
Dit blijkt niet voldoende te zijn om grote
software-systemen efficiënt te kunnen
onderhouden!
Bij het maken van nieuwe systemen is er door de
top-down-analyse geen stimulans om eerder gemaakte
modules te hergebruiken!
JAVA
1
1.
INLEIDING: O.O. - concepten en
O.O. - terminologie
Wat zijn nu de wensen voor software-ontwikkeling en –onderhoud?
1. Data abstractie (zie ook $ 8.16)
behoefte om data te groeperen
Vb. de leeftijd, het geslacht en de naam van een persoon.
Zo maken we een nieuw datatype = abstract datatype.
Java-programmeurs: eigen user-defined types, klassen genoemd
JAVA
2
1.
INLEIDING: O.O. - concepten en
O.O. - terminologie
Wat zijn nu de wensen voor software-ontwikkeling en –onderhoud?
1. Data abstractie (zie ook $ 8.16)
Elke klasse bevat:
data (instantie variabelen of members)
én een aantal methodes, die de data kunnen manipuleren
Een klasse is een specificatie voor objecten.
Een object is een instantie van een klasse, dat gemaakt is volgens deze
specificatie.
BESLUIT : de focus in Java ligt veeleer op het maken van objecten, dan op
het schrijven van methodes zoals in procedurele programmeertalen
JAVA
3
1.
INLEIDING: O.O. - concepten en
O.O. - terminologie
Wat zijn nu de wensen voor software-ontwikkeling en –onderhoud?
2. Inkapseling (zie ook $8.16)
Het wijzigen van de interne opbouw van een abstract datatype, mag
weinig of géén invoed hebben op de rest van de programmatuur!
Hoe wordt dit gerealiseerd?
De methodes die manipulaties uitvoeren op de attributen, bij elkaar
plaatsen, gekoppeld aan dat type = black box of object! Met andere
woorden, de implementatiedetails zitten verborgen in het object zelf!
data (en methodes)
methodes
JAVA
4
1.
INLEIDING: O.O. - concepten en
O.O. - terminologie
Wat zijn nu de wensen voor software-ontwikkeling en –onderhoud?
3. Overerving (zie H9)
Overerving is een mechanisme waarbij software opnieuw wordt gebruikt:
nieuwe klassen worden gecreëerd vertrekkende van bestaande klassen,
waarbij de attributen en methodes worden geërfd van de basisklasse en
uitgebreid met nieuwe mogelijkheden, noodzakelijk voor de nieuwe
klasse = afgeleide klasse.
Schematisch:
basisklasse
erft van
afgeleide klasse
JAVA
5
1.
INLEIDING: O.O. - concepten en
O.O. - terminologie
Wat zijn nu de wensen voor software-ontwikkeling en –onderhoud?
4. Polymorfisme (zie H10)
Met polymorfisme is het mogelijk om systemen te ontwerpen en te
implementeren, die eenvoudig uitbreidbaar zijn!
Klassen die nog niet bestaan tijdens de ontwikkeling van het programma,
kunnen mits kleine of geen wijzigingen toegevoegd worden aan het
generieke deel van het programma, op voorwaarde dat deze klassen deel
uitmaken van de hiërarchie.
De enige delen van het programma, die gewijzigd of uitgebreid moeten
worden, zijn deze die rechtstreeks te maken hebben met de specifieke
klasse, die toegevoegd wordt.
JAVA
6
2. Implementatie van een abstract
datatype met een klasse
De naam van een class
•
moet met een letter beginnen
•
mag geen gereserveerd woord uit Java zijn
•
•
iedere class binnen een bepaald bereik (= package) moet een
unieke naam hebben
afspraak in de Java-wereld:
- de naam van een klasse begint met een hoofdletter
(vb. Rekening, Televisie, Klant, Time1)
- ieder woord na het eerste woord begint met een hoofdletter
(vb. SpaarRekening, WebServer)
JAVA
7
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De klasse Time1
•
data (attributen, members):
hour, minute, second (integers)
•
methoden (lidfuncties):
- Time1() = constructor
- setTime() = set-methode
- toUniversalString() = conversie-methode
- toString() = conversie-methode
JAVA
8
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Een klasse beschrijven
public class Time1 extends Object // Object uit package java.lang
{ ….
}
- extends betekent : afgeleid van
- Time1 erft de data en de methoden van de moederklasse Object en
voegt er nieuwe eigenschappen aan toe
- Elke klasse in java is een directe of indirecte subklasse van de
superklasse Object -> elke klasse erft de 11 methoden, waaronder
toString() en equals() uit de klasse Object
JAVA
9
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Volgens de UML - notatie
Object
erft van
Time1
JAVA
10
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Attribuutwaarden bijhouden
•
per attribuut een variabele in de class declareren
•
ieder object van de klasse krijgt zijn eigen attributen
•
de attributen private declareren : enkel toegankelijk voor de
class-code, m.a.w. voor de methoden in de klasse, niet
toegankelijk voor de buitenwereld (= principe van inkapseling)
public class Time1 [extends Object] // mag weggelaten worden
{
private int hour, minute, second;
…..
}
JAVA
11
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Attributen van een klasse krijgen een beginwaarde
Type variabele
Beginwaarde
byte, short, int, long
0
float, double
0.0
char
Teken met unicode waarde 0
boolean
false
reference
null
public class Time1 [extends Object]
{
private int hour, minute, second;
…..
}
0
0
0
JAVA
12
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Een methode in een klasse
• wordt gebruikt om de data in een object van de klasse te manipuleren
-> heeft meestal weinig of geen parameters
-> eenvoudige call
• krijgt meestal de toegangsclausule public
JAVA
13
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Een methode in een klasse
• is bijgevolg buiten de klasse zelf toegankelijk wanneer een programma
(een andere klasse) een referentie naar een Time1-object heeft, want een
methode van een klasse moet via een referentie naar een object
aangesproken worden, tenzij de methode static is:
Time1 time = new Time1(); // constructie van een Time1-object
time.setTime(13,27,6); // oproep non-static methode setTime
time.toString(); // oproep non-static methode toString
• mehodes die private zijn, worden de helpmethodes genoemd, vermits
deze enkel door andere methodes van dezelfde klasse kunnen aangeroepen
worden!
JAVA
14
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Een speciale methode: de constructor
•
doel = object initialiseren
•
methode met dezelfde naam als de klasse
public Time1()
{
setTime(0,0,0);
}
•
mag geen retuntype hebben (zelfs geen void), wel parameters
JAVA
15
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Een speciale methode = de constructor
•
wordt automatisch aangeroepen bij aanmaak van een nieuw object :
Time1 time;
time = new Time1();
OF
Time1 time = new Time1();
•
de constructor geeft impliciet een referentie naar het geïnitialiseerde
object terug
•
een constructor mag overladen worden -> meerdere mogelijkheden om
een object te initialiseren (zie $8.7)
JAVA
16
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De overige methoden in de class Time1 : setTime()
public void setTime (int h, int m, int s)
{
hour = ((h >= 0 && h < 24) ? h : 0);
minute = ((m >= 0 && m < 60) ? m : 0);
second = ((s >= 0 && s < 60) ? s : 0);
}
•
•
•
•
public -> algemeen toegankelijk
methode van de klasse Time1 -> heeft toegang tot hour, minute en
second
drie argumenten om het tijd-object te initialiseren
De methode controleert de parameters op geldige waarde -> een tijdobject bevat altijd geldige data (later met exceptions werken om de
JAVA van de foutieve gegevens)! 17
buitenwereld op de hoogte te brengen
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De overige methoden in de class Time1 : toUniversalString()
import java.text.DecimalFormat;
public String toUniversalString () // Geen parameters!
{ DecimalFormat twoDigits = new DecimalFormat(" 00");
return twoDigits.format(hour) + ":" + twoDigits.format(minute) + ":" +
twoDigits.format(second);
}
•
public -> algemeen toegankelijk
JAVA
18
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De overige methoden in de class Time1 : toUniversalString()
•
methode van de klasse Time1: heeft toegang tot hour, minute en second
•
Maakt gebruik van de bibliotheekklasse DecimalFormat uit het pakket
java.text, om het formaat van een getal vast te leggen: elk getal moet uit
twee cijfers bestaan en eventueel vooraan aangevuld met een nul (08 of 12)
•
De methode format uit de klasse DecimalFormat formateert het getal en
geeft het als een String-object terug. De verschillende strings worden
samengevoegd met de +-operator en de verkregen string is de
returnwaarde.
JAVA
19
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De overige methoden in de class Time1 : toStandardString()
public String toStandardString ()
{
DecimalFormat twoDigits = new DecimalFormat(" 00");
return ((hour == 12 || hour == 0) ? 12 : hour % 12) + ":" +
twoDigits.format(minute) + ":" + twoDigits.format(second) ":" +
(hour < 12 ? " AM" : " PM") ;
}
• public -> algemeen toegankelijk
• methode van de klasse Time1 -> heeft toegang tot hour, minute en second
• De methode toStandardString dient om het Tijd-object te converteren naar
een string, zoals in de methode toUniversalString(), maar nu gevolgd door
een PM- of AM-indicator (11:05:56 PM).
JAVA
20
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De klasse Time1 ( = domeinklasse) gebruiken in een applicatie
import javax.swing.JOptionPane;
public class TimeTest1
{
public static void main (String args[])
{
Time1 time = new Time1(); // constructor
String output = " de initiële universele tijd is : " + time.toUniversalString()
+ " \nde initiële standaardtijd is : " + time.toStandardString()
time.setTime(13,27,6);
output += " \n\nde universele tijd na setTime is : " + time.toUniversalString()
+ " de standaardtijd na setTime is : " + time.toStandardString();
time.setTime(99,99,99);
output += " \n\nna het toekennen van foutieve waarden : " +
" de universele tijd is : " + time.toUniversalString() +
" de standaardtijd is : " + time.toStandardString();
JOptionPane.showMessageDialog(null,output,"Testing Class Time1",
JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
}
JAVA
21
2. Implementatie van een abstract
datatype met een klasse (vervolg)
De klasse Time1 ( = domeinklasse) gebruiken in een applicatie
JAVA
22
2. Implementatie van een abstract
datatype met een klasse (vervolg)
Merk op :
• de attributen hour, minute en second zijn private en dus niet
toegankelijk buiten de klasse waarin ze gedefinieerd zijn -> wordt er
iets gewijzigd aan de datarepresentatie, bijv. we geven de volledige
tijd weer als een aantal seconden verlopen sedert middernacht, dan
kan de gebruiker dezelfde methodes gebruiken en hij zal dezelfde
resultaten krijgen => de implementatie van een klasse is verborgen
voor de gebruiker
• methodes toUniversalString en toStandardString krijgen geen
argumenten, aangezien ze tot dezelfde klasse behoren als de
instantievariabelen van het Time1-object waarop ze inwerken en er
dus impliciet toegang toe hebben
• klassen vereenvoudigen het programmeren, vermits de gebruiker
van de klasse enkel betrokken is bij de publieke operaties, die
JAVA
ingekapseld zijn in het object
23
3. De scope van een klasse
• Class scope
– bevat attributen (members) en methoden
– members zijn toegankelijk voor alle klassemethoden
– je verwijst naar een member
* in de klasse met behulp van zijn naam
* buiten de klasse (als public) met
objectReferenceName.objectMemberName
Voorbeeld:
int rij[] = new int[10];
System.out.println(rij.length);
JAVA
24
3. De scope van een klasse (vervolg)
• Block scope
- variabelen gedefinieerd binnen een methode, zijn enkel binnen
deze methode gekend = lokale variabelen
- deze variabelen hebben geen beginwaarde
- wanneer een lokale variabele dezelfde naam heeft als een member
van de klasse, dan verbergt de lokale variabele de andere binnen de
scope van de methode
- een verborgen member is toch toegankelijk binnen de methode
door het sleutelwoord this gevolgd door een punt voor de naam van de
member te zetten (zie ook $ 8.5)!
JAVA
25
3. De scope van een klasse (vervolg)
Voorbeeld:
public void setTime (int hour, int minute, int second)
{
this.hour = ((hour >= 0 && hour < 24) ? hour : 0);
this.minute = ((minute >= 0 && minute < 60) ? minute : 0);
this.second = ((second >= 0 && second < 60) ? second : 0);
}
JAVA
26
OEFENING: Klasse Doos ontwerpen
Maak een klasse Doos
Attributen: lengte, breedte en hoogte (double)
Methodes:
• setDoos() met 3 parameters, die gecontroleerd moeten worden op
geldigheid (> 0) ; indien niet geldig, geef de member de waarde 1.0
• methode inhoud() om de inhoud van een doos te bepalen
•methode toStandardString definiëren voor deze klasse: de string moet
zowel de attributen als de inhoud van de doos bevatten
JAVA
27
OPLOSSING
class Doos
{
private double lengte, breedte, hoogte;
}
public setDoos ( double deLengte, double deBreedte, double deHoogte )
{
lengte = (deLengte > 0 ? deLengte:1.0);
breedte = (deBreedte > 0 ? deBreedte:1.0);
hoogte = (deHoogte > 0? deHoogte:1.0);
}
public double inhoud()
{
return lengte * breedte * hoogte;
}
public String toStandardString ()
{
return ( " Lengte: " + lengte + "\n" + " Breedte: " + breedte + "\n" + " Hoogte: " + hoogte()
+ "\n" + "Inhoud: " + inhoud() );
}
JAVA
28
4. Toegangscontroles voor leden van de klasse
• private : niet toegankelijk voor de gebruikers van de klasse; enkel de
methodes van de klasse hebben rechtstreekse toegang tot de private
members
Voorbeeld:
public class TimeTest2
{
public static void main(String args[])
{
Time1 time = new Time1();
time.hour = 7; // FOUT!!! hour is een private attribuut!
}
}
• public : algemeen toegankelijk; de publieke interface van de klasse zijn de
publieke methodes
JAVA
29
4. Toegangscontrole voor leden van de
klasse (vervolg)
Principe van inkapseling:
gebruikmaken van private members en publieke methoden, waarmee we
toegang hebben tot de data!
Voorbeelden van dergelijke methoden zijn de accessor-methode en de
mutator-methode.
* accessor-methode of getXxx()-methode: om de waarde van het
attribuut xxx voor de buitenwereld kenbaar te maken
Voorbeeld:
public int getHour()
{
return hour;
}
JAVA
30
4. Toegangscontrole voor leden van de
klasse (vervolg)
* mutator-methode of setXxx()-methode: om het private attribuut
Xxx een waarde te geven, die meegegeven wordt als parameter en die
gecontroleerd wordt op geldigheid
Voorbeeld:
public void setHour(int h)
{
hour = ((h >= 0 && h < 24) ? h : 0);
}
• protected : zie H9
• package : zie $8.12
JAVA
31
5. Gebruikmaken van de this-referentie
• ieder object heeft toegang tot een referentie naar zichzelf = this
• wordt impliciet gebruikt om te refereren naar zowel de attributen
als de methoden van een object
• Java is zuinig met geheugen, door van elke methode van de klasse
maar één versie te bewaren, die dan door elk object van de klasse
aangeroepen wordt. Elk object heeft echter zijn eigen versie van de
attributen!
• als in een methode een parameter dezelfde naam heeft als een
member van de klasse, dan gebruiken we expliciet this om de
member aan te spreken, anders refereren we naar de parameter!
Uitgewerkt voorbeeld: klassen SimpleTime en ThisTest
JAVA
32
6. Objecten intialiseren: constructors
Instantie-variabelen kunnen als volgt geïnitialiseerd worden:
• expliciet, wanneer ze gedeclareerd worden in de klasse-body
• impliciet op hun default-waarden (primitieve numerieke variabelen
worden op 0 gezet, booleans krijgen de waarde false en referenties
worden gelijk aan null gesteld)
• in een constructor zonder parameters
• later, na de creatie van het object, via set-methodes
• in een constructor met parameters: wanneer een programma
een object van een klasse instantieert, kan het zgn. initializers
tussen haakjes, na de klasse, meegeven; deze worden als
argumenten doorgegeven aan de constructor
Voorbeeld: DecimalFormat twoDigits = new DecimalFormat(" 00");
JAVA
33
6. Objecten intialiseren: default constructor
Een default-constructor
• is een constructor zonder parameters
Voorbeeld:
public Time1()
{ setTime(0,0,0);
}
• wordt automatisch gemaakt door de compiler als u geen andere
constructors binnen die klasse maakt, maar doet in feite niets!
• wordt niet gemaakt als u wel andere constructors maakt
• de default-constructor van een klasse roept de default-constructor
van de superklasse aan, enz… ; als de basisklasse geen defaultconstructor heeft, geeft de compiler een foutmelding
• de body van de default-constructor mag leeg zijn: public Time1() { }
JAVA
34
OEFENINGEN
1. Maak een klasse Rechthoek.
Attributen: breedte en hoogte (double)
Methodes:
• constructor met 2 parameters
• Methode om de oppervlakte te bepalen
• Methode om de omtrek te bepalen
• De methode toStandardString definiëren voor deze klasse: de
string moet zowel de attributen als de omtrek en de oppervlakte
bevatten
2. Voeg in de klasse Doos een constructor toe, die gebruik maakt van
de reeds aanwezige setdoos()-methode.
JAVA
35
OPLOSSINGEN (1)
class Rechthoek
{
private double lengte, breedte;
public Rechthoek ( double deLengte, double deBreedte )
{
lengte = deLengte;
breedte = deBreedte;
}
public double omtrek()
{
return 2 * lengte + 2 * breedte;
}
public double oppervlakte()
{
return lengte * breedte;
}
public String toStandardString ()
{
return ( " Lengte: " + lengte + "\n" + " Breedte: " + breedte + "\n" + " Omtrek: " + omtrek()
+ "\n" + " Oppervlakte: " + oppervlakte() );
}
}
JAVA
36
OPLOSSINGEN (2)
class Doos
{
private double lengte, breedte, hoogte;
}
public Doos (double l, double b, double h )
{
setDoos(l,b,h);
}
public setDoos ( double deLengte, double deBreedte, double deHoogte )
{
lengte = (deLengte > 0 ? deLengte:1.0);
breedte = (deBreedte > 0 ? deBreedte:1.0);
hoogte = (deHoogte > 0? deHoogte:1.0);
}
public double inhoud()
{
return lengte * breedte * hoogte;
}
public String toStandardString ()
{
return ( " Lengte: " + lengte + "\n" + " Breedte: " + breedte + "\n" + " Hoogte: " + hoogte()
+ "\n" + "Inhoud: " + inhoud() );
}
JAVA
37
7. Gebruikmaken van overladen constructoren
Herhaling: overloaden van methodes
Een methode mag meerdere keren in een klasse voorkomen als
• het aantal parameters verschillend is
• het type van de parameters verschillend is
Met andere woorden de paramerlijst moet verschillend zijn!
Een verschillend returntype is niet voldoende!
JAVA
38
7. Gebruikmaken van overladen constructoren
Overloaden van de constructor
Wanneer we een constructor in een klasse gaan overladen, kan
een object op verschillende manieren geïnitialiseerd worden!
Afhankelijk van het aantal argumenten of van het type van de
argumenten, wordt de overeenkomstige constructor aangeroepen!
Zorg ervoor, dat de compiler nooit twijfelt welke constructor juist
moet uitgevoerd worden!
JAVA
39
7. Gebruikmaken van overladen
constructoren (vervolg)
Voorbeeld:
public class Time2
{
private int hour, minute, second;
public Time2() // default-constructor – versie 1
{ setTime(0,0,0); }
public Time2(int h) // versie 2
{ setTime(h,0,0); }
public Time2(int h, int m) // versie 3
{ setTime(h,m,0); }
JAVA
40
7. Gebruikmaken van overladen
constructoren (vervolg)
Voorbeeld:
public Time2(int h, int m, int s) // versie 4
{ setTime(h,m,s); }
public Time2(Time2 time) // versie 5
{ this(time.hour,time.minute,time.second); }
OF
public Time2(Time2 time)
{ setTime(time.hour,time.minute,time.second); }
}
JAVA
41
7. Gebruikmaken van overladen
constructoren (vervolg)
Merk op :
 Een constructor wordt in een andere constructor van
dezelfde klasse opgeroepen via this, niet door middel
van zijn naam!
 Gebruiken we in een constructor een andere
constructor van dezelfde klasse, dan moet deze
aanroep steeds als eerste statement staan!
JAVA
42
7. Gebruikmaken van overladen
constructoren (vervolg)
Voorbeeld: toepassing van class Time2
public class TimeTest3
{
public static void main (String args[])
{
Time2 t1, t2, t3, t4, t5, t6; // declaratie van 6 referenties
t1 = new Time2();
// 00:00:00
t2 = new Time2(2);
// 02:00:00
t3 = new Time2(21,34);
// 21:34:00
t4 = new Time2(12,25,42); // 12:25:42
t5 = new Time2(27,74,99); // 00:00:00
t6 = new Time2(t4);
// 12:25:42
…… // zie p. 358
}
} // uitvoerscherm zie p. 359
JAVA
43
OEFENINGEN
1. Maak een klasse Complex.
Members: real en imaginair (double) (real + imaginair * i)
Methodes:
• default-constructor (real = imaginair = 0.0)
• constructor met één parameter (imaginair = 0.0)
• constructor met 2 parameters
• methode om de optelling van 2 complexe getallen te bepalen
• methode om de aftrekking van 2 complexe getallen te bepalen
• De methode toStandardString definiëren voor deze klasse; de string
moet het complex getal als volgt weergeven: (real,imaginair)
2. Voeg in de klasse Doos een default-constructor toe, die gebruik maakt
van de reeds aanwezige constructor en die alle members op 1.0 zet.
JAVA
44
OPLOSSINGEN (1)
class Complex
{
private double real;
private double imaginair;
public Complex()
{
this( 0.0, 0.0 ); // aanroep constructor met 2 parameters
}
public Complex( double r )
{
this( r, 0.0 );
}
public Complex( double r, double i )
{
real = r;
imaginary = i;
}
JAVA
45
OPLOSSINGEN (1)
// Optelling van 2 complexe getallen
public Complex optelling( Complex right )
{
return new Complex( real + right.real,
imaginair + right.imaginair );
}
// Aftrekking van 2 complexe getallen
public Complex aftrekking( Complex right )
{
return new Complex( real - right.real,
imaginair - right.imaginair );
}
// Geeft de Stringrepresentatie weer van een complex getal
public String toStandardString()
{ return "(" + real + ", " + imaginair + ")"; }
}
JAVA
46
OPLOSSINGEN (2)
class Doos
{
private double lengte, breedte, hoogte;
public Doos()
{
this(1.0,1.0,1.0);
}
public Doos (double l, double b, double h )
{
setDoos(l,b,h);
}
public setDoos ( double deLengte, double deBreedte, double deHoogte )
{
lengte = (deLengte > 0 ? deLengte:1.0);
breedte = (deBreedte > 0 ? deBreedte:1.0);
hoogte = (deHoogte > 0? deHoogte:1.0);
}
}
// ....
JAVA
47
8. Set- en Get- methodes gebruiken
• getXxx()-methode of accessor-methode
 om de waarde van het attribuut xxx voor de buitenwereld kenbaar te
maken -> public!
 controleert de formattering en de manier waarop het attribuut wordt
weergegeven
 andere methoden kunnen via de getXxx()-methode de waarde van
het attribuut lezen
• setXxx()-methode of mutator-methode
 om het private attribuut Xxx een waarde te geven door de
buitenwereld -> public!
 de waarde wordt meegegeven als parameter en gecontroleerd op
geldigheid, vb. 37 wordt geweigerd als dag van de maand
Uitgewerkt voorbeeld: class Time3 + applet TimeTest4
JAVA
48
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Fig. 8.7: Time3.java
// Time3 klassedefinitie met set- en get-methoden
import java.text.DecimalFormat;
public class Time3
{ private int hour;
// 0 - 23
private int minute; // 0 - 59
private int second; // 0 - 59
private variabelen zijn niet
direct toegankelijk voor objecten
andere klassen
// Time3 constructor initialiseert elke member van
op nul
// Deze methode verzekert ons dat het Time object start in een geldige status
public Time3()
{
setTime( 0, 0, 0 );
}
// Time3 constructor: hour wordt geïnitialiseerd via een waarde die we doorgeven
// minute en second default op 0 geïnitialiseerd
public Time3( int h )
{
setTime( h, 0, 0 );
}
JAVA
49
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Time3 constructor: hour and minute geïnitialiseerd
// second default op 0
public Time3( int h, int m )
{
setTime( h, m, 0 );
}
// Time3 constructor: hour, minute and second geïnitialiseerd
public Time3( int h, int m, int s )
{
setTime( h, m, s );
}
// Time3 constructor: met een ander Time3 object geïnitialiseerd
public Time3( Time3 time )
{
// roep de Time3 constructor met 3 argumenten op
this( time.getHour(), time.getMinute(), time.getSecond() );
}
JAVA
50
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Set- Methoden
// We geven een nieuwe tijd-waarde gebruikmakend van de universele tijd.
// We testen de waarden op geldigheid. Ongeldige waarden zetten we op nul.
public void setTime( int h, int m, int s )
{
setHour( h ); // hour instellen
Mutator methoden laten objecten
setMinute( m ); // minute instellen
toe om private variabelen te
setSecond( s ); // second instellen
manipuleren
}
// controleer en stel het uur in
public void setHour( int h )
{
hour = ( ( h >= 0 && h < 24 ) ? h : 0 );
}
// controleer en stel de minuten in
public void setMinute( int m )
{
minute = ( ( m >= 0 && m < 60 ) ? m : 0 );
}
// controleer en stel de seconden in
public void setSecond( int s )
{
second = ( ( s >= 0 && s < 60 ) ? s : 0 );
JAVA
51
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Get Methoden
// de waarde van hour
public int getHour()
{
return hour;
}
// de waarde van minute
public int getMinute()
{
return minute;
}
// de waarde van second
public int getSecond()
{
return second;
}
// conversie naar een String in het universele tijdformaat
public String toUniversalString()
{
DecimalFormat twoDigits = new DecimalFormat( "00" );
}
return twoDigits.format( getHour() ) + ":" +
twoDigits.format( getMinute() ) + ":" +
twoDigits.format( getSecond() );
JAVA
52
98
99
// conversie naar String in standaard tijdformaat
100 public String toStandardString()
101 {
102
DecimalFormat twoDigits = new DecimalFormat( "00" );
103
104
return ( ( getHour() == 12 || getHour() == 0 ) ?
105
12 : getHour() % 12) + ":" + twoDigits.format( getMinute() ) +
106
":" + twoDigits.format( getSecond() ) +
107
( getHour() < 12 ? " AM" : " PM" );
108 }
109
110 } // einde class Time3
JAVA
53
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Fig. 8.8: TimeTest4.java
// Demonstratie van de klasse Time3 class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimeTest5 extends JApplet implements ActionListener
{
Declaratie en creatie van
een Time3 object
private Time3 time;
private JLabel hourLabel, minuteLabel, secondLabel;
private JTextField hourField, minuteField, secondField, displayField;
private JButton tickButton;
// Creatie van een Time3 object en opbouw van de GUI
public void init()
{
time = new Time3();
JAVA
54
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Container container = getContentPane();
container.setLayout( new FlowLayout() );
// opbouw van hourLabel en hourField
hourLabel = new JLabel( "Set Hour" );
hourField = new JTextField( 10 );
container.add( hourLabel );
container.add( hourField );
JTextFields laat de
gebruiker toe om de tijd
te specifiëren
// opbouw van minuteLabel en minuteField
minuteLabel = new JLabel( "Set minute" );
minuteField = new JTextField( 10 );
container.add( minuteLabel );
container.add( minuteField );
// opbouw van secondLabel en secondField
secondLabel = new JLabel( "Set Second" );
secondField = new JTextField( 10 );
container.add( secondLabel );
container.add( secondField );
JAVA
55
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// opbouw van displayField
displayField = new JTextField( 30 );
displayField.setEditable( false );
container.add( displayField );
// opbouw van tickButton
tickButton = new JButton( "Add 1 to Second" );
container.add( tickButton );
// registreer de event-handlers
// deze applet is de ActionListener, die de methode actionPerformed bevast
// actionPerformed behandelt de events die gegenereerd worden door hourField,
// minuteField, secondField en tickButton
hourField.addActionListener(this);
minuteField.addActionListener(this);
secondField.addActionListener(this);
tickButton.addActionListener(this);
displayTime(); // update tekst in displayField en statusbalk
}
JAVA
56
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// afhandelen van de button- en de textvakken events
public void actionPerformed( ActionEvent event )
{
// tickButton event
if ( event.getSource() == tickButton )
tick();
// hourField event
else if ( event.getSource() == hourField ) {
time.setHour( Integer.parseInt( event.getActionCommand() ) );
hourField.setText( "" );
}
// minuteField event
else if ( actionEvent.getSource() == minuteField ) {
time.setMinute(Integer.parseInt( minuteField.getText());
minuteField.setText( "" );
}
// secondField event
else if ( actionEvent.getSource() == secondField ) {
time.setSecond(Integer.parseInt( actionEvent.getActionCommand() ) );
secondField.setText( "" );
}
displayTime(); // update displayField en statusbalk
}
JAVA
57
92
// update displayField en de statusbalk van de applet container
93
public void displayTime()
94
{
95
displayField.setText( "Hour: " + time.getHour() + "; Minute: " +
96
time.getMinute() + "; Second: " + time.getSecond() );
97
98
showStatus( "Standard time is: " + time.toStandardString() +
99
"; Universal time is: " + time.toUniversalString() );
100
101
}
102
103
// verhoog second met één en update hour/minute als het nodig is
104
public void tick()
105
{
106
time.setSecond( ( time.getSecond() + 1 ) % 60 );
107
108
if ( time.getSecond() == 0 ) {
109
time.setMinute( ( time.getMinute() + 1 ) % 60 );
110
111
if ( time.getMinute() == 0 )
112
time.setHour( ( time.getHour() + 1 ) % 24 );
113
}
114
115
}
116
117 } // einde class TimeTest5
JAVA
58
Voor en na het instellen van het uur
JAVA
59
Voor en na het instellen van de minuten
JAVA
60
Voor en na het instellen van de seconden
JAVA
61
Twee keer klikken op “add 1 to second”
JAVA
62
OEFENING:
UITBREIDING VAN DE KLASSE RECHTHOEK
Voeg get- en set-methodes voor de members toe.
De set-methodes controleren de waarden op geldigheid.
De attributen moeten tussen 0 en 20 (beide inbegrepen) liggen.
Is dit niet het geval, dan worden deze default op 1.0 gezet.
JAVA
63
OPLOSSING
class Rechthoek
{ private double lengte, breedte;
public Rechthoek()
{
setLengte( 1.0 );
setBreedte( 1.0 );
}
public Rechthoek(double deLengte, double deBreedte )
{
setLengte( deLengte );
setBreedte( deBreedte );
}
JAVA
64
OPLOSSING
public void setLengte( double deLengte )
{
lengte = ( deLengte > 0.0 &&
deLengte < 20.0 ? deLengte : 1.0 );
}
public void setBreedte( double deBreedte )
{
breedte = ( deBreedte > 0 &&
deBreedte < 20.0 ? deBreedte : 1.0 );
}
JAVA
65
OPLOSSING
public double getLengte()
{
return lengte;
}
public double getBreedte()
{
return breedte;
}
}
JAVA
66
9. Samenstelling:
objecten als attribuut van andere klassen
• Composition = een klasse bevat referenties naar objecten van
andere klassen als members (een vorm van software reuse!)
• Voorbeeld: (zie fig 8.9 – fig. 8.11)
public class Date { ….}
public class Employee
{
private String firstName, lastName;
private Date birthDate, hireDate;
JAVA
67
9. Samenstelling:
objecten als attribuut van andere klassen (vervolg)
// constructor
public Employee (String first,String last, Date dateOfBirth, Date dateOfHire)
{
firstName = first; // referentietoekenning
lastName = last; // referentietoekenning
birthDate = dateOfBirth;
hireDate = dateOfHire;
}
Opmerking: Een member-object moet niet onmiddellijk geïnitialiseerd
worden met argumenten van de constructor. In dat geval wordt de
default-constructor (als beschikbaar!) van het member-object aangeroepen. Via een set-methode kan deze later nog een waarde krijgen.
JAVA
68
9. Samenstelling:
objecten als attribuut van andere klassen (vervolg)
import javax.swing.JOptionPane;
public class EmployeeTest
{
public static void main (String args[])
{
Date birth = new Date (7,24,1949); // oproep van de
Date hire = new Date (3,12,1988); // Date-constructor
// oproep van de Employee-constructor
Employee employee = new Employee ("Bob", "Jones", birth, hire);
JOptionPane.showMessageDialog (null,
employee.toEmployeeString(), "Testing Class Employee",
JOptionPane.INFORMATION_MESSAGE);
}
}
System.exit(0);
JAVA
69
10. Garbage collection
• Garbage collection
– geeft geheugen aangemaakt met new in de constructor
terug aan het systeem
– Java verricht dit automatisch; een object is gemarkeerd als
afval wanneer er geen referentie meer is naar dat object
– kan ook expliciet aangeroepen worden met System.gc();
– véél gebruik van lokale variabelen, die verwijzen naar objecten,
kan de performantie verlagen; telkens een lokale variabele
out of scope gaat, wordt het object gemarkeerd als afval!
Gebeurt dit veel in een korte tijd, dan geeft dit een grote
belasting voor de garbage collector.
JAVA
70
10. Garbage collection (vervolg)
• Finalizer methode
– wordt steeds aangeroepen door de garbage collector om de
“termination housekeeping” op het object te verrichten, juist
voor de garbage collector het geheugen voor het object terugeist
– heeft steeds de naam finalize, heeft geen parameters en geen
returnwaarde (void)
– elke klasse in java erft deze methode van de klasse
java.lang.Object met een lege body
– wordt zeer weinig gebruikt!
– wordt protected gedeclareerd (zie H. 9)
Voorbeeld: zie class Employee in $8.11
JAVA
71
11. Static klassemembers
–
–
–
static klassevariabelen van een klasse bestaan maar één
keer voor alle objecten van die klasse; de objecten delen de
static variabele
wordt gebruikt om klasse-informatie in op te slaan;
= globale variabele met een klasse-scope
Voorbeelden:
1) het aantal objecten dat reeds van een klasse aangemaakt is
2) de aangroeiintrest op een spaarrekening
Voordelen:
1) minder geheugenruimte nodig bij gedeelde variabelen
2) minder tijd nodig om de variabele te wijzigen (één keer)
JAVA
72
11. Static klassemembers (vervolg)
- als public: toegankelijk via een object van de klasse of via de
klassenaam gevolgd door een punt: vb. Math.PI
- als private: enkel toegankelijk voor methoden van de klasse
(zie class Employee: de constructor en finalize())
- bestaat reeds wanneer er nog geen objecten van de
klasse bestaan; dan enkel toegankelijk via de klasse zelf
(als public) of via een public static methode (als private), die
ALTIJD via de klasse wordt aangeroepen: vb. Math.random()
(zie class Employee: de methode getCount())
JAVA
73
11. Static klassemembers (vervolg)
Een static methode
- heeft geen toegang tot gewone klassemembers (nonstatic) of tot
andere methoden uit de klasse
- bestaat reeds wanneer er nog geen objecten van de
klasse bestaan;
- heeft geen this-referentie
Voorbeeld : de klassen Employee en EmployeeTest
JAVA
74
12. Final instantie-variabelen (attributen)
• sleutelwoord final geeft aan dat een variabele niet wijzigbaar is
private final int INCREMENT = 5;
Iedere poging om een final variabele (= constante) te wijzigen via een
toekenning, resulteert in een compiler-fout!
• Een dergelijk attribuut MOET geïnitialiseerd worden bij declaratie of in
een constructor van de klasse!
• Respecteer het principe van het kleinste voorrecht en declareer een
attribuut, dat niet mag gewijzigd worden, altijd final!
Voorbeeld: zie class IncrementTest
JAVA
75
13. Packages maken
Een package
• is een verzameling van klassen en interfaces die bij elkaar horen
• geeft verfijndere toegangsrechten tussen klassen, interfaces en methoden
• lost naamconflicten tussen klassen op, want 2 klassen met dezelfde naam,
worden onderscheiden door de naam van de package waartoe ze behoren
• bevordert het gebruik van reeds bestaande klassen, door deze eenvoudig
met een import-statement uit andere packages te importeren
JAVA
76
13. Packages maken (vervolg)
De naam van een package
• afspraak: in kleine letters
• hiërarchisch van opbouw:
 java.lang
 javax.swing
 deitel.com.jhtp5 (Java How To Program 5de editie)
 be.hogent.tin
• uw reverse firma-url als begin van de naam = unieke naam wereldwijd
• packages worden uiteindelijk directories (mappen)
JAVA
77
13. Packages maken (vervolg)
Een package maken
• definieer een public class; als de klasse niet public is, kan ze enkel
gebruikt worden door andere klassen binnen dezelfde package
• kies een naam voor de package (com.deitel.jhtp5.ch08) en voeg het volgende package-statement toe aan de source-file:
package com.deitel.jhtp5.ch08; // zie p. 380
JAVA
78
13. Packages maken (vervolg)
LET OP:
- dit package - statement moet als eerste statement in de file staan,
dus voor de importstatements! Dit zijn de enige statements die buiten
de body van een klasse kunnen staan.
-een sourcefile kan maar één package-statement hebben, m.a.w. een
class/interface kan maar tot één package behoren!
-een sourcefile kan wel meerdere klassen/interfaces bevatten, maar
slechts één klasse kan public zijn!
JAVA
79
13. Packages maken (vervolg)
Een package gebruiken
• bij compilatie wordt de .class-file in de geschikte package directory-structuur gezet;
wanneer de directory nog niet bestaat, creëert de compiler deze eerst.
Een extra optie (-d), dat we moeten doorgeven aan de javac-compiler, specifieert
waar de directories, die gespecifieerd zijn in het package-statement,
moeten gecreëerd of gelocaliseerd worden:
javac –d . Time1.java
Dit betekent, dat de eerste directory die gespecifieerd is in de packagenaam, in de
huidige directory (.) moet geplaatst worden.
De klassenaam is nu com.deitel.jthp5.ch08.Time1.
Je kan deze volledige naam gebruiken of je kan de klasse importeren met het statement
import com.deitel.jthp5.ch08.Time1; en de korte naam Time1 in jouw programma
gebruiken.
JAVA
80
13. Packages maken (vervolg)
Een classpath gebruiken
•
De compiler volgt steeds een bepaalde volgorde om de klassen die hij nodig heeft, te zoeken!
1. De standaard Java-klassen
2. De extension-klassen
3. Het classpath; default = huidige directory
Het classpath kan gewijzigd worden
a. Gebruikmaken van de –classpath optie bij de javac-compiler
b. De CLASSPATH-variabele instellen via een set-commando
In beide gevallen is het classpath een lijst van directories en/of archive-files
gescheiden door ;. Een archive-file is een individuele file, dat directories of
andere files bevat en ze heeft normaal een filenaam die eindigt op .jar of .zip.
•
De werking van de interpreter is te vergelijken met de compiler. Hij gaat op dezelfde manier
te werk om de nodige files te vinden. Je kan eveneens gebruik maken van de –classpath optie
bij de java-interpreter.
JAVA
81
14. Package-toegankelijkheid
Mogelijke toegangelijkheid voor attributen en methoden van een klasse:
• private
• public
• protected (zie H. 9)
• package (= default)
Een attribuut of methode met package-access is enkel toegankelijk voor alle
klassen binnen dezelfde package (directory). Deze klassen hebben via een
referentie naar een object rechtstreeks toegang, dus zonder te moeten werken
met get- of set-funties, tot elkaars members met package-access (<->
inkapseling)! Packagetoegankelijkheid heeft geen effect wanneer uw
programma maar uit één klasse bestaat!
JAVA
82
14. Package-toegankelijkheid (vervolg)
Voorbeeld:
class PackageData // klasse met package-toegankelijkheid
{
int number; // attribuut met package-access
String string; // attribuut met package-access
// ….
}
public class PackageDataTest
{
public static void main(String[] args)
{
PackageData packageData = new PackageData();
packageData.number = 77;
packageData.string = "Goodbye";
//…
}
JAVA
}
83
15. Herbruikbaarheid van software
• Java bevat duizende klassen in de Java-API => re-use van
bestaande klassen => Rapid application development (RAD)
(Java API-documentatie : java.sun.com/j2se/1.3/docs/api/index.html)
• Belangrijk : nieuwe klassen voldoende becommentariëren (ev. met
javadoc) en verduidelijken met UML-schema’s -> bevordert het
opnieuw gebruiken van de bestaande klassen
• Programmeren in Java = nieuwe klassen
ontwerpen én gebruikmaken van bestaande
klassen
JAVA
84
OEFENING
Rode draad: klasse Rekening
Constructoren:
•
Maak een constructor met drie argumenten die zowel het
rekeningnummer, als het beginsaldo en de houder volgens de
opgegeven waarden invult.
•
Maak een tweede constructor met twee argumenten die
defaultwaarde 0 invult voor saldo en die de meegegeven
argumenten als waarde voor rekeningnummer en houder gebruikt.
Maak gebruik van de 1e constructor!
JAVA
85
OEFENING
Rode draad: klasse Rekening
Methodes:
•
Maak voor deze constructoren gebruik van een methode setSaldo
(saldo moet positief zijn), setHouder (houder mag geen lege string
zijn) en setNummer (de laatste 2 cijfers moeten de rest vormen
van de eerste 10 gedeeld door 97 of ze moeten 97 zijn als deze
rest 0 is – indien niet juist, verbeter dan de laatste 2 cijfers).
•
Indien een van de set-methodes de waarde die opgegeven werd,
heeft moeten aanpassen, dan wordt een foutmelding gegenereerd
JAVA
86
OEFENING
Rode draad: klasse Rekening
Methodes (vervolg):
•
Definieer ook de nog ontbrekende get-methodes: getHouder en
getNummer (getSaldo bestaat reeds).
•
Maak tenslotte nog een methode toRekeningString die de waarden
van alle attributen netjes afbeeldt
JAVA
87
OPLOSSING
class Rekening
{
private long rekeningNr;
private double saldo;
private String houder;
public Rekening (long rNr, double s, String h)
{
setNummer(rNr);
setSaldo(s);
setHouder(h);
}
public Rekening (long rNr, String h)
{
this (rNr, 0, h);
JAVA
}
88
OPLOSSING
public void setNummer (long rNr)
{
long eerste10 = rNr / 100;
long rest = rNr % 100;
}
if (eerste10 % 97 == rest || (eerste10 % 97 == 0 && rest == 97))
rekeningNr = rNr;
else
{
JOptionPane.showMessageDialog (null,
"Verkeerd rekeningnummer – " +
"laatste 2 cijfers werden aangepast!");
rekeningNr = (eerste10 * 100) + (eerste10 % 97);
}
JAVA
89
OPLOSSING
public void setSaldo (double hetSaldo)
{
if (hetSaldo >= 0)
saldo = hetSaldo;
else
{
JOptionPane.showMessageDialog (null, "Fout saldo – "
+ "saldo werd op 0 gezet!");
hetSaldo = 0;
}
}
JAVA
90
OPLOSSING
public void setHouder (String deHouder)
{
if (deHouder == "")
{
JOptionPane.showMessageDialog (null,
"Houder is niet juist - \"onbekend\" ingevuld");
houder = "onbekend";
}
else
houder = deHouder;
}
JAVA
91
OPLOSSING
public long getNummer ()
{
return rekeningNr;
}
public double getSaldo ()
{
return saldo;
}
public String getHouder ()
{
return houder;
}
JAVA
92
OPLOSSING
public String toRekeningString ()
{
long eerste3 = rekeningNr / 1000000000;
long rest = rekeningNr % 100;
long midden7 = (rekeningNr / 100) % 10000000;
DecimalFormat twee, drie, zeven, tweeNaKomma;
twee = new DecimalFormat("00");
drie = new DecimalFormat("000");
zeven = new DecimalFormat("0000000");
tweeNaKomma = new DecimalFormat ("0.00");
String rString = drie.format(eerste3) + "-" + zeven.format(midden7) +
"-" + twee.format(rest);
}
}
return "De rekening met rekeningnummer " + rString +
"\nstaat op naam van " + houder +
"\nen bevat " + tweeNaKomma.format(saldo) + " euro";
JAVA
93
Download