Commentaar in Java kan één van de drie volgende vormen aannemen:
//
tot aan de regelovergang
worden overgeslagen./*
en */
worden
overgeslagen, ongeacht regelovergangen.javadoc
dit
commentaar gebruiken om automatisch documentatie te
genereren, behorende bij de code.
Aan variabelen, klassen en methoden worden namen gegeven, zodat de compiler ze kan onderscheiden. De namen kunnen bestaan uit een willekeurige verzameling tekens (hoofd- of kleine letters), getallen, onderstreping (_) of het dollarteken. Namen kunnen niet beginnen met een getal.
Java gebruikt een aantal specifieke tekens als scheidingsteken. De meest gebruikelijke is de puntkomma (;) maar er is ook:
Symbool | Beschrijving |
() | Deze bevat een parameterlijst bij het definiëren en aanroepen van methoden (functies of procedures). Wordt ook gebruikt om de volgorde van rekenkundige operatoren om te gooien, om expressies binnen stuurinstructies te bevatten of om conversies tussen datatypes aan te geven. |
{} | Hierbinnen geeft men waarden van automatisch geïnitialiseerde vectoren. Wordt ook gebruikt om blokken code te begrenzen binnen een klasse, methode of voor het definiëren van een lokaal stuk code. |
[] | Voor matrix definitie en referentie naar waarden binnen een matrix. |
; | Scheidingsteken voor Java zinnen. |
, | Scheiding in namen van variabele declaraties.
Scheiding van zinnen in een FOR -constructie. |
. | Scheiding tussen pakket- sub-pakket- en klasse namen en scheiding tussen de variabele of methode en de gerefereerde variabele. |
abstract | double | int | super |
boolean | else | interface | switch |
break | extends | long | synchronized |
byte | false | native | this |
byvalue | final | new | threadsafe |
case | finally | null | throw |
catch | float | package | transient |
char | for | private | true |
class | goto | protected | try |
const | if | public | void |
continue | implements | return | while |
default | import | short | |
do | instanceof | static |
In het vorige artikel werd beweerd dat Java volledig objectgeoriënteerd was. Edoch, voor de efficiency zijn er acht eenvoudige data typen gemaakt die geen objecten zijn. Tevens hebben deze data typen, vanwege uitwisselbaarheid met andere computers, een strikt gedefinieerd waardenbereik.
Eenvoudige data typen kunnen in vier groepen worden ingedeeld.
TYPE | NAAM | GROOTTE | BEREIK |
Integer | long | 64 | -9.223.372.036.854.775.808
a 9.223.372.036.854.775.807 |
int | 32 | -2.147.483.648
a 2.147.483.647 |
|
short | 16 | -32.768 a 37.767 | |
byte | 8 | -128 a 127 | |
Drijvende komma | float | 32 | 3.4 e-038 a 3.4 e+038 |
double | 64 | 1.7 e-308 a 1.7 e+308 | |
Karaktertekens | char | 16 | Unicode |
Logisch | boolean | True of False |
Over het algemeen wordt een variabele als volgt gedeclareerd:
identifier type [=value] [,identifier [=value]......]; |
type
een basis Java type kan zijn of een
klasse of zelfs een interface. Bij initialisatie van de variabele
moet de expressie van hetzelfde type zijn (of van een uitwisselbaar
type) als de declaratie.
Voorbeelden:
int a = 4, b, c=7; char c; myclass class; |
{}
). Een variabele verliest zijn waarde buiten dat bereik.
De meeste programmeertalen definiëren twee soorten bereik; globaal en lokaal. Dit sluit echter niet goed aan bij het objectgeoriënteerde model van Java. Bij dit model worden de twee belangrijkste bereiken gedefinieerd door een klasse en een methode.
int
type is groot genoeg voor de
opslag van een byte
type, dus is er geen expliciete
conversie nodig. Numerieke typen zijn niet uitwisselbaar met
char
of boolean
typen. Als we een
int
waarde aan een byte
type willen
toekennen, zullen we een expliciete conversie als volgt moeten forceren:
(type) value |
type
staat voor het data type waarnaar moet worden
geconverteerd. Bijvoorbeeld:
int a; char b; a=(int) b; |
Bij conversie van een drijvende komma getal naar een integer getal verliest
men de waarde achter de komma:
int a; double d= 125.43; a=(int) d;De variabele heeft de waarde 125. byte b; int i=257; b=(byte) i; b heeft de waarde 1, als resultaat van het delen van 257 door
256. 256 is namelijk het maximum van een byte type.
byte b; double d= 340.123; b=(byte) d;Waarbij b de waarde 84 zal hebben. |
Operator | Beschrijving |
+ | Optellen |
- | Aftrekken |
* | Vermenigvuldigen |
/ | Delen |
% | Modulo (restwaarde bij deling) |
++ | Verhogen (met 1) |
+= | Optellen en toekennen |
-= | Aftrekken en toekennen |
*= | Vermenigvuldigen en toekennen |
/= | Delen en toekennen |
%= | Modulo en toekennen |
-- | Verlagen (met 1) |
int a=38; double d=41.95; int c=a%10;< double e=d%10; |
c
bevat 8. De variabele e
is 1,95.
De operatoren met toekenning zijn handig bij constructies als:
a = a + 4;
is gelijk aan a+=4;
a = a % 2;
is gelijk aan a%=2;
Gewoonlijk kunnen we zinnen als de volgende maken:
variabele = variable bewerking expressie;
kan worden vervangen
door: variabele bewerking= expressie;
.
integer, long, int, short, char
en byte
typen,
waarbij de operand bits worden gewijzigd.
Operator | Beschrijving |
~ | NOT-operatie op bitniveau |
& | AND-operatie op bitniveau |
| | OR-operatie op bitniveau |
/\ | XOR-operatie op bitniveau |
>> | Schuif bits naar rechts |
>>>> | Bits naar rechts, links aanvullen met nullen |
<< | Bits naar links |
&= | Bit-AND en toekennen |
|= | Bit-OR en toekennen |
/\= | Bit-XOR en toekennen |
>>= | Bits naar rechts en toekennen |
>>>>= | Bits naar rechts, links aanvullen met nullen en toekennen |
<<= | Bits naar links en toekennen |
Operator | Beschrijving |
= = | Is gelijk aan? |
!= | Ongelijk aan? |
> | Groter dan? |
< | Kleiner dan? |
>= | Groter of gelijk aan? |
<= | Kleiner of gelijk aan? |
True
en False
en zijn het geen numerieke
waarden.
Operator | Beschrijving |
& | logische AND |
| | logische OR |
/\ | logische XOR(eXclusive OR) |
|| | snelle OR |
&& | snelle AND |
! | logische NOT |
&= | AND en toekennen |
|= | OR en toekennen |
/\= | XOR en toekennen |
= = | Gelijk aan |
!= | Niet gelijk aan |
?: | Ternaire If-then-else |
OR
operatie levert het resultaat
True
als de eerste operand deze waarde heeft. Analoog hiermee
levert de AND
operatie de waarde False
wanneer de
eerste operand de waarde False
heeft.
Het formaat van de ternaire operator:
expressie1 ? expressie2 : expressie3
Wanneer expressie1
waar is (waarde: True
), zal
expressie2
worden uitgevoerd. Anders wordt
expressie3
uitgevoerd.
Volgorde (hiërarchie) van operatoren:
( ) | [ ] | . | |
++ | -- | ~ | ! |
* | / | % | |
+ | - | ||
>> | >>>> | << | |
> | >= | < | <= |
= = | != | ||
& | |||
' | |||
| | |||
&& | |||
|| | |||
?: | |||
= | Op= |
Groep | Stuuropdracht | Beschrijving |
Selectie | if |
if ( voorwaarde ) opdracht1; else ; opdracht2; |
diverse if's |
If (voorwaarde ) opdracht; else if (voorwaarde) opdracht; else if (voorwaarde) opdracht; . ... else opdracht; |
|
switch |
switch (uitdrukking){ case waarde1: opdracht; break; case waarde2: opdracht; break; . ... default : opdracht; } |
|
Herhaling | while |
while (voorwaarde) { opdracht; } |
do while |
do { opdrachten; } while (voorwaarde) |
|
for |
for (initialisatie, voorwaarde, iteratie) { opdrachten; } |
|
Verspringen | break | Uit een switch springen.
Uit een lus springen |
continue | Slaat de rest van de lus over en begint aan de volgende cyclus | |
return | Retourneer uit een routine (methode) |
Een klasse is het model voor een object en een object is de instantie van een klasse. Java ondersteunt geen globale functies of variabelen dus moeten alle acties (methoden) gedefinieerd worden in de klasse zelf.
Een klasse definitie begint met het keyword class
. Een doorsnee
klasse definitie ziet er als volgt uit:
Class klasse_naam { Type eerste_variabele; Type tweede_variabele; . . ... type xxxe_variable; type methode_naam(lijst_van_parameters){ //body van de methode } . . .. type naam_van_de_methode(lijst_van_parameters){ //body van de methode } } |
Twee dingen zijn nodig voor het verkrijgen van objecten van een klasse:
Het dynamisch toewijzen van geheugen voor het object en een referentie ernaar creëren.
new
operator.
Formaat:
variabele = new naam_van_de_klasse(); |
variabele
een variabele is van de klasse die we willen
maken en naam_van_de_klasse
de naam is van de klasse die wordt
gemaakt. Het creëren van een object kan als volgt grafisch worden
weergegeven:
type naam_van_de_methode (lijst_van_parameters) { //body van de methode } |
type
is het type dat wordt geretourneerd door de methode. Dit kan
ieder type zijn, ook een klasse type of geen type (void
,
er wordt niets geretourneerd).
De lijst van parameters is een opsomming van telkens een type met een naam, gescheiden door een dubbelpunt. De parameters zijn variabelen die de waarde krijgen van de argumenten bij aanroep van de methode. Wanneer een methode geen parameters heeft, zal de parameterlijst leeg zijn.
Methoden die een waarde retourneren (anders dan void
)
gebruiken de instructie:
return waarde; |
waarde
de te retourneren waarde bevat.
Het gebruik van methoden binnen Java is een krachtig mechanisme. Vandaar dat we ons, voor de rest van dit artikel, zullen richten op het gebruik hiervan.
Laten we voor we verdergaan echter, het voorgaande even verduidelijken met behulp van een eenvoudig voorbeeld.
We gaan een klasse maken die de inhoud berekent van een rechthoekige
doos (een zwembad bijvoorbeeld):
Code | Commentaar |
class capaciteit { double lengte; double breedte; double hoogte; void BerekenVolume () { double volume ; volume = lengte*breedte*hoogte; System.out.println("Volume: " + volume); } } |
We hebben hier een klasse gedefinieerd, genaamd capaciteit ,
met drie instantievariabelen, lengte, breedte en
hoogte . Verder bevat de klasse een methode om de inhoud te
berekenen. We zullen het bestand capaciteit.java noemen. Na
compilatie wordt het bestand capaciteit.class aangemaakt.
|
Code | Commentaar |
class voorbeeld { public static void main(String Arg[]){ capaciteit p1=new capaciteit(); capaciteit p2=new capaciteit(); p1.lengte = 16; p1.breedte=3; p1.hoogte=2; // p2.lengte = 25; p2.breedte=6; p2.hoogte=3; // p1.BerekenVolume(); // p2.BerekenVolume(); } } |
Twee variabelen zijn aangemaakt: p1 en
p2 . Met behulp van new worden twee objecten van de
capaciteit klasse aangemaakt waaraan kan worden gerefereerd via de variabelen
p1 en p2 .
Daarna geven we waardes aan de variabelen van de objecten.
De methode
Idem voor het object waar
|
p1.BerekenVolume()
wordt uitgevoerd, wordt de code in
BerekenVolume()
door Java geïnterpreteerd. Wanneer alle
instructies uit zijn gevoerd, zal worden teruggekeerd naar de aanroepende
routine, alwaar men doorgaat de eerstvolgende instructie ná de aanroep
uit te voeren.
Methoden met parameters. Retourwaarden
Het gros van de methoden gebruikt parameters. Hierdoor kunnen methoden een meer algemene toepassing krijgen. Methoden kunnen ook waarden retourneren. We kunnen dus methoden maken die werken op een groot aantal waarden en die kunnen worden ingezet bij verschillende situaties.
We zullen het voorbeeld verbeteren:
Code | Commentaar |
class capacieit { double BerekenVolume (double l, double b, double h) { double volume=l*b*h ; return volume; } } |
De methode BerekenVolume() is aangepast en
ontvangt nu drie parameters. De definitie zegt ook dat hij een
double type retourneert. Dit gebeurt middels de instructie
return volume . |
class voorbeeld { public static void main(String Arg[]){ capaciteit p1=new capaciteit(); capaciteit p2=new capaciteit(); double vol; vol=p1.BerekenVolume(10,3,2); System.out.println("Volume: " + vol) // vol=p2.BerekenVolume(25,5,2); System.out.println("Volume: " + vol); } } |
De aanroep van de methode wordt vergezeld door de gevraagde
parameters. De geretourneerde waarde wordt in de vol variabele
gezet, die van hetzelfde type moet zijn. |
Een constructor van een klasse heeft precies dezelfde naam als de klasse zelf
en wordt gedefinieerd als een methode. Hij wordt uitgevoerd tijdens
een objectcreatie, bij de new
-operatie dus.
Constructors retourneren geen waarden, maar impliciet het type van de klasse.
Een constructor zal de toestand van een object op de juiste manier
initialiseren. Hierdoor heeft de aanroepende code direct een object dat klaar
is voor gebruik. Standaard zullen constructors instantievariabelen
initialiseren. Net als bij methoden kunnen constructors ook parameters hebben
om zo de bruikbaarheid te vergroten. Laten we ons voorbeeld weer aanpassen
om alle nieuwe inzichten hierin te verwerken.
Code | Commentaar |
Class capaciteit { double lengte; double breedte; double hoogte; // capaciteit(double l, double a, double p){ length=l; width=a; height=p; } // void BerekenVolume () { double volume ; volume=lengte*breedte*hoogte; return volume; } } |
Een constructor wordt op dezelfde manier in een klasse gedefinieerd als een methode. Hij heeft alleen dezelfde naam als de klasse waarin hij wordt gedefinieerd maar zonder type-definitie. De constructor initialiseert de instanties van de variabelen met de ontvangen argumenten. |
class voorbeeld { public static void main(String Arg[]) { capaciteit p1=new capaciteit(10,5,2); capaciteit p2=new capaciteit(25,6,2); double vol; vol=p1.BerekenVolume(); System.out.println("Volume: " + vol); // vol=p2.BerekenVolume(); System.out.println("Volume: " + vol); } } |
new creëert een instantie van de klasse,
waarbij de parameters voor de constructor worden doorgegeven.
|
Desondanks is er een finalize()
-methode voor het "afsluiten" of
"opruimen" van een object. Deze methode wordt aangeroepen op het moment dat
het object wordt verwijderd. De methode kan acties bevatten die vlak voor
verwijdering moeten worden uitgevoerd.
Polymorfisme
Polymorfisme (meerdere methoden voor één interface) is één van de hoekstenen van objectgeoriënteerd programmeren. Java implementeert dit middels method overload.
Meerdere methoden met dezelfde naam kunnen binnen één en dezelfde klasse worden gedefinieerd. Ze moeten echter wel verschillen in de parameterlijst of het geretourneerde type. Wanneer een dergelijke overloaded methode wordt aangeroepen, zal de Java interpretator de argumentenlijst en retourtypen gebruiken om de juiste methode te vinden om aan te roepen.
Iedere versie van een dergelijke methode kan iets totaal anders doen, hoewel polymorfisme hier niet voor is uitgevonden en het dan al gauw onoverzichtelijk wordt. Het is dus de bedoeling dat deze methoden iets gemeenschappelijk hebben. Net als methoden, kunnen ook constructors polymorfisme hebben.
Doorgifte van argumenten
Programmeertalen hebben over het algemeen twee mechanismen voor het doorgeven van argumenten:
Data afschermen
Een andere hoeksteen van objectgeoriënteerd programmeren is het inkapselen, wat betekent dat data wordt gepaard aan de code die het gebruikt. Inkapselen kan ook data afschermen. Dit betekent dat slechts een deel van de code toegang heeft tot elementen van een klasse (variabelen, methoden...).
Toegang specificeert men in Java met: public
(publiek),
private
(privé) of protected
(beschermd).
Een element dat public
is gedefinieerd is toegankelijk vanuit
alle delen van een programma. private
elementen zijn alleen
toegankelijk voor methoden van de eigen klasse. Standaard (indien niet
expliciet opgegeven), zijn alle elementen public
.
protected
wordt gebruikt bij overerving, wat het
volgende onderwerp is van dit artikel.
Klasse B
eigenschappen laten erven van superclass A
wordt B
als volgt gedaan:
Class B extends A { // definitie van de klasse } |
B
erft daarmee alle elementen van klasse A
.
Deze laatste is een autonome klasse die ook op zichzelf kan worden
gebruikt. Klasse B
kan op zijn beurt een superclass
zijn voor weer andere klassen.
Java staat geen overerving toe van meerdere algemene klassen naar één specifieke klasse.
private
elementen van een algemene klasse zijn niet toegankelijk
voor de specifieke klasse. Wanneer een specifieke klasse moet refereren aan
de algemene klasse waar hij direct van erft dan kan dit middels
super
. Zo kunnen we constructors en andere elementen van de
algemene klasse aanroepen die afgeschermd worden door de specifieke klasse.
Wanneer een methode van een specifieke klasse een zelfde naam en type heeft als een methode in de algemene klasse dan is deze methode overschreven. Dit is één van de krachtiger mechanismen in Java, genaamd Dynamische selectie. Het betekent dat de beslissing welke methode aan te roepen pas tijdens uitvoer van het programma wordt genomen, afhankelijk van het gerefereerde datatype.
In het volgende artikel gaan we verder in op de kracht van overerving met daarbij abstracte klassen, interfaces etc.