Programmeren in Java/Klassen

Uit Wikibooks
Ga naar: navigatie, zoek


Programmeren in Java In ontwikkeling. Revisiedatum: onbekend

  1. Inleiding Redelijk ontwikkeld. Revisiedatum: 22 augustus 2008
  2. Basis Goed ontwikkeld. Revisiedatum: 24 november 2007
  3. In- & uitvoer In ontwikkeling. Revisiedatum: 24 november 2007
  4. Stringbewerkingen In ontwikkeling. Revisiedatum: 24 november 2007
  5. Arrays Nog vrijwel niets. Revisiedatum: 24 november 2007
  6. Collections Nog vrijwel niets. Revisiedatum: 24 november 2007
  7. Exceptions Redelijk ontwikkeld. Revisiedatum: 24 november 2007
  8. Generics Nog vrijwel niets. Revisiedatum: 24 november 2007
  9. Ingebouwde functies Nog vrijwel niets. Revisiedatum: 20 januari 2007
  10. Multithreading Nog vrijwel niets. Revisiedatum: 20 januari 2007
  11. GUI In ontwikkeling. Revisiedatum: 24 november 2007
  12. JSP: JavaServer Pages Redelijk ontwikkeld. Revisiedatum: 24 november 2007

Klassen

  1. Klassen Goed ontwikkeld. Revisiedatum: 24 november 2007
  2. Overerving In ontwikkeling. Revisiedatum: 20 januari 2007
  3. Geavanceerde klassen In ontwikkeling. Revisiedatum: 24 november 2007

Design Patterns

  1. Strategy Pattern Nog vrijwel niets. Revisiedatum: 26 december 2010

Appendices

  1. Appendix A: Installatie In ontwikkeling. Revisiedatum: 24 november 2007
  2. Appendix B: Javadoc In ontwikkeling. Revisiedatum: 24 november 2007


Eigenlijk is programmeren in Java het schrijven van classes (klassen in het Nederlands). Een klasse is een samenhangend geheel van variabelen en methodes.

Klassen[bewerken]

De definitie van een class is eenvoudig:

Java-code:

1: class MyClass { }

is een correcte definitie van een class, die helaas niets doet. Door het toevoegen van methodes wordt het mogelijk om de class iets te laten doen:

Java-code: Dummy.java

1: public class Dummy {
2:   public void doSomething() {
3:     System.out.println("Hallo"); 
4:   }
5: }

Deze niet al te spannende variant op "Hello world" laat een aantal belangrijke eigenschappen van een methode zien. Op regel 2 wordt een methode beschreven met de naam doSomething. De keywords public en void geven aan door welke Java classes deze methode te gebruiken is en wat de methode als waarde teruggeeft. In dit geval is de methode door alle classes in de JVM aan te roepen. void geeft aan dat de methode niets teruggeeft.

Java-code: Omdraaier.java

1: public class Omdraaier {
2:  public String draaiOm(String invoer) {
3:    return new StringBuilder(invoer).reverse().toString(); 
4:  }
5: }

Nu gebeuren er interessantere dingen. De methode draaiOm op regel 2 geeft aan dat deze aangeroepen kan worden met een String als argument. Bovendien geeft de methode een String terug. Het zal geen verbazing wekken dat deze methode de invoer omgedraaid teruggeeft. Verder wordt er een andere class gebruikt, StringBuilder. Er wordt een nieuw object aangemaakt van de class StringBuilder. Bij het aanmaken van de StringBuilder wordt de waarde van de variabele invoer meegegeven en wordt de reverse() methode van StringBuilder aangeroepen. Vervolgens wordt van dit resultaat weer een String gemaakt door het aanroepen van toString(). Deze String wordt teruggegeven als resultaat van de methode doordat er een return voor staat.

Structuur[bewerken]

De structuur van een class is in feite simpel: binnen de definitie van een class worden velden en methoden beschreven. Over het algemeen zullen deze velden en methoden met elkaar samenhangen.

Java-code: HogerLager.java

 1: public class HogerLager {
 2:   private int antwoord = 7;
 3:   private int aantalPogingen = 0;
 4:   private final int maxPogingenToegestaan = 3;
 5:   public void raad(int getal) {
 6:     aantalPogingen++;
 7:     if (aantalPogingen > maxPogingenToegestaan) {
 8:        System.out.println("Maximale aantal pogingen is verbruikt.");        
 9:      }
10:     if (getal == antwoord) {
11:       System.out.println("Gefeliciteerd!");       
12:     }  
13:     if (getal < antwoord) {
14:       System.out.println("Hoger, nog " + (maxPogingenToegestaan - aantalPogingen) + " keer raden");      
15:     }
16:     else {
17:       System.out.println("Lager, nog " + (maxPogingenToegestaan - aantalPogingen) + " keer raden");       
18:   }
19:   public HogerLager() { }
20: }

Deze class implementeert het spelletje hoger-lager. Om dit te kunnen spelen moet er een te raden waarde zijn, een teller die bijhoudt hoeveel pogingen er geweest zijn, een instelling voor het maximale aantal pogingen dat is toegestaan en een manier om degene die raadt te vertellen wat de uitkomst is. Al deze zaken zijn aanwezig in deze class.

Velden[bewerken]

Velden bevatten data. Deze data kan van een primitief type zijn, zoals int of char, maar ook een type als StringBuilder of een instantie van een zelf gedefinieerde klasse. Velden zijn onder te verdelen in twee soorten: velden per klasse en velden per instantie. Een klein voorbeeld kan dit verschil duidelijker maken:

Java-code: Velden.java

 1: class Velden { 
 2:   private static int aantal;
 3:   private int volgnummer;
 4:   
 5:   public Velden() {
 6:     aantal++;
 7:     volgnummer = aantal;
 8:   }
 9:   
10:   public int getVolgnummer() {
11:     return volgnummer;
12:   }
13: 
14:   public int getAantal() {
15:     return aantal;
16:    }
17: }

In dit voorbeeld wordt elke keer als er een Velden object wordt aangemaakt de waarde van aantal met 1 verhoogd. Het volgnummer krijgt dezelfde waarde als het aantal op dat moment. Het belangrijke verschil tussen deze twee velden wordt aangegeven door het keyword static. Dit geeft aan dat de variabele aantal gedeeld wordt door alle instanties van de klasse Velden. Het veld volgnummer is niet static en elk object (of instantie) van het type Velden kan hier een eigen waarde in opslaan.

Constructors[bewerken]

Een constructor wordt aangeroepen op het moment dat er een nieuwe instantie van een klasse wordt gemaakt. Elke keer als het keyword new wordt gebruikt betekent dit dat er een constructor wordt aangeroepen. Constructors zijn methoden met het verschil dat een constructor geen waarde teruggeeft en dat de naam van een constructor altijd gelijk is aan de naam van de klasse.

In Velden.java is een constructor gedefinieerd op de regels 5 tm 8. Elke Java klasse moet een constructor hebben, al is het mogelijk om zelf een klasse te schrijven die geen constructor bevat. Voor zo'n klasse maakt de compiler automatisch een constructor aan.

Methoden[bewerken]

Methoden zijn de acties die een klasse uit kan voeren. In de voorgaande voorbeelden zijn diverse voorbeelden te vinden, zoals de methode getAantal() in Velden.java. Een methode heeft een naam, bijvoorbeeld getAantal. Een methode geeft mogelijk een waarde terug, in dit geval een int. Verder kan een methode een zogenaamde access modifier hebben, in dit geval is dat public. Verder kan een methode ook parameters verwachten:

Java-code: Optellen.java

 1: class Optellen { 
 2:
 3:   public int telOp(int a, int b) {
 4:     return a + b;
 5:   }   
 6: }

De methode telOp verwacht twee parameters, elk van het type int. Een declaratie van een methode bestaat dus uit een access modifier (zie ook de volgende sectie voor meer informatie), een return type, een naam en een lijst met parameters (die leeg mag zijn). Verder bestaat de implementatie van de methode uit een code blok, in Optellen.java is dat alleen regel 4, maar in HogerLager.java is een veel langere methode te vinden.

Een speciaal return type is void. Een methode die void als return type heeft geeft niets terug. Bijgevolg wordt het sleutelwoord "return" weggelaten in methodes die niets teruggeven.

Pass by value of pass by reference?[bewerken]

Java maakt gebruik van pass by value voor het doorgeven van parameters aan een methode. De methode gebruikt dus een kopie van de variabele die het meekrijgt van een aanroepende methode. Dit houdt in dat toekenningen die je in de methode doet op deze variabele niet gebeuren op de eigenlijke variabele van de aanroepende methode maar enkel op de kopie. Is de variabele geen primitief type (int, long, double) maar een referentie type (object), en je zou een toekenning doen dan heeft dit ook geen effect op het object dat meegegeven werd. Je kent de referentie immers een andere waarde toe niet het object zelf. Het object kan wel gewijzigd worden met deze referentie die een kopie is van de oorspronkelijke referentie meegegeven met de methode aanroep.

Stel nu dat we de volgende code hebben: de class PassByValue met een public attribuut myValue = 10.

Java-code: PassByValue.java

 1: public class PassByValue 
 2:{
 3:	public int myValue =10;
 4:}

Java-code: Program.java

1: public class Program 
2: {		
3:	public void doeIets(int c,int d)
4:	{
5:		c=20;
6:		System.out.println("c:"+c+" d:"+d); //c:20 d:4
7:	}
8:	
9:	public void doSomething(PassByValue pbv)
10:	{
11:		pbv.myValue =20;
12:		pbv=new PassByValue();
13:		System.out.println(pbv.myValue);// 10
14:		pbv.myValue=30;
15:	}
16:	public static void main(String[] args)
17:	{
18:		Program pr=new Program();
19:		int a=5;
20:		int b=4;
21:		pr.doeIets(a,b); 
22:		System.out.println("a:"+a+" b:"+b);//a:5 b:4
23:		PassByValue pbv = new PassByValue();
24:		pr.doSomething(pbv);
25:		System.out.println(pbv.myValue); //20
26:	}	
27}

Voor de primitieve typen: We zien op regel 21 dat aan de methode doeIets de waarde 5 aan a en 4 aan b wordt meegegeven. c is een kopie van variabele a en d één van b. Nu kennen we aan c de waarde 20 toe en we zien dat na terugkeer in main a nog steeds de waarde 5 heeft.

Voor de referentie typen: Oorspronkelijk heeft in PassByValue het attribuut myValue de waarde 10. We geven het PassByValue object mee met methode doSomething. We wijzigen de waarde van myValue via de kopie van de referentie in doSomething naar waarde 20. (We kunnen dus het object wijzigen). Dan in regel 12 laten we pbv naar een nieuw object wijzen (toekenning) en wijzigen de waarde van myValue naar 30. De laatste regel (25) in main toont nog steeds de waarde 20 voor myValue. De referentie pbv in main na afloop van doSomething wijst nog steeds naar de oorspronkelijke pbv en niet naar het nieuwe PassByValue object aangemaakt in doSomething op regel 12. Dit laatste zou anders geweest zijn moest Java pass by reference zijn, dan was myValue 30 op regel 25.

public, private, protected[bewerken]

In Java is het idee van zichtbaarheid erg belangrijk. Java kent voor een class 4 niveaus van zichtbaarheid die aangegeven kunnen worden met 3 verschillende zogenaamde access modifiers (Zie module 2).

  • public geeft aan dat iets zichtbaar is voor alle classes in een JVM
  • protected geeft aan dat iets zichtbaar is binnen een package of voor subclasses
  • geen access modifier geeft aan dat er sprake is van zichtbaarheid binnen een package
  • private geeft aan dat iets zichtbaar is voor alleen de eigen class

Access modifiers kunnen worden toegepast op klassen, methoden en velden, maar niet alle modifiers hebben in alle gevallen een zinvolle betekenis.

Laten we beginnen met de acces modifiers voor een class. Een class kan public of default zichbaarheid hebben, de andere niveaus van zichtbaarheid hebben geen zin voor een class. De volgende definities laten zien hoe de zichtbaarheid van een class wordt aangegeven. Merk op dat default access impliciet is:

Java-code:

1: public class MyPublicClass { }
2: class MyDefaultClass {}

Velden en methoden kunnen alle 4 niveaus van zichtbaarheid hebben:

Java-code: AccessDemo.java

 1: package myPackage;
 2: public class MyPublicClass {
 3:   public int algemeenZichtbaar = 0;
 4:   protected int beperktZichtbaar = 0;
 5:   int nogBeperkterZichtbaar = 0;
 6:   private int nietZichtbaarVanBuiten = 0;
 7:
 8:   public void algemeenAanroepbaar() { }
 9:   protected void ietsMinderAlgemeenAanroepbaar() { }
10:   void nogMinderAlgemeenAanroepbaar() { }
11:   private void nietAanroepbaarVanBuiten() { }
12: }

In het voorgaande voorbeeld wordt een public class aangemaakt in het package myPackage. Een package is een groepering van classes die met elkaar samenhangen. De class MyPublicClass is public, dat wil zeggen dat de class zichtbaar is voor alle classes binnen de JVM. MyPublic class heeft 4 velden en 4 methoden die alle vier de zichtbaarheids niveaus laten zien.

Merk op dat de zichtbaarheid van een methode of veld voor een andere class pas relevant wordt op het moment dat de class zichtbaar is voor die andere class.

Het public veld en de public methode zijn zichtbaar voor alle classes in de JVM. Dit betekent ook dat een object van een andere class de waarde van algemeenZichtbaar kan aanpassen.

Het protected veld en de protected methode zijn alleen zichtbaar voor classes in hetzelfde package als MyPublicClass, of voor subclasses van MyPublicClass.

Het default veld en de default methode zijn alleen zichtbaar voor classes in hetzelfde package als MyPublicClass.

Het private veld en de private methode zijn alleen zichtbaar voor MyPublicClass.

final, abstract, static, synchronized, native, strictfp[bewerken]

Naast de hiervoor genoemde access modifiers zijn er nog andere modifiers die gebruikt kunnen worden voor klassen, velden of methoden.

De eerste hiervan is final. final geeft aan dat er geen andere implementatie of waarde van iets mogelijk is.

Java-code: Optellen.java

 1: final class Optellen { 
 2:
 3:   public int telOp(int a, int b) {
 4:     return a + b;
 5:   }   
 6: }

De final in regel 1 geeft aan dat het niet mogelijk is om de klasse Optellen te gebruiken om van te erven (zie module 6 voor meer informatie over dit onderwerp).

Java-code: AbstractOptellen.java

 1: abstract class AbstractOptellen { 
 2:
 3:   public abstract int telOp(int a, int b);
 4:
 5: }

abstract bij een klasse (zie regel 1 in AbstractOptellen.java) geeft aan de klasse niet geinstantieerd kan worden. Het idee hierachter is dat een abstracte klasse wordt uitgebreid door andere klassen (zie module 6, geavanceerde klassen voor meer informatie).

Een methode kan ook abstract zijn. Op regel 3 in AbstractOptellen.java is daar een voorbeeld van te zien. Wat meteen opvalt is dat de methode wel wordt beschreven maar geen code bevat die iets doet. De ; na de argumentenlijst is dan ook het einde van de definitie van een abstracte methode. Deze methode kan worden geimplementeerd door een subklassen van AbstractOptellen.

Zodra een klasse een abstract methode bevat moet de klasse zelf ook abstract zijn. Het omgekeerde is niet noodzakelijk waar.

static geeft aan dat iets bij de klasse hoort, en niet bij de instanties van die klasse. In Velden.java is hier een voorbeeld van te vinden: het veld aantal is static, dat wil zeggen dat alle instanties van Velden dit veld met elkaar delen.

Een methode kan ook static zijn. Een static methode kan worden aangeroepen zonder dat er een instantie van de klasse is:

Java-code: StaticVoorbeeld.java

 1: class StaticVoorbeeld { 
 2:
 3:   public static int telOp(int a, int b) {
 4:     return a + b;
 5:   }   
 6: }

Nu de methode telOp static is gemaakt is het mogelijk geworden om deze aan te roepen met StaticVoorbeeld.telOp(1, 2); De naam van de klasse wordt dus gebruikt om aan te geven welke methode moet worden uitgevoerd.

synchronized is een andere modifier die voor methodes gebruikt kan worden. synchronzed geeft aan dat maar 1 thread tegelijk de synchronized methode kan aanroepen. Multi-threading is een geavanceerd onderwerp dat we hier niet verder zullen behandelen.

Andere modifiers zijn native en strictfp. We vermelden deze alleen voor de volledigheid. native wil zeggen dat de implementatie van de methode in platform-specifieke code is, over het algemeen in C. strictfp wil zeggen dat een klasse of methode alle floating point berekeningen uitvoert volgens de IEEE 754 standaard.

Package-organisatie[bewerken]

Een klasse bevindt zich in een package. Zo bevindt Random zich in het package java.util en kan op een van volgende manieren aangegeven worden waar de compiler deze klasse kan vinden.

import java.util.*;
import java.util.Random;

Alle packagenamen worden met kleine letters geschreven en moeten uniek zijn. Bovendien verwacht de compiler dat de onderdelen een afspiegeling zijn van de opslag op het filesysteem. Zo bevindt de map util zich in de directory java. Sommige IDE's, zoals de gratis NetBeans, maken automatisch deze mappen aan.

Soms worden voor packagenamen, die uniek moeten zijn, omgekeerde URL-domeinnamen genomen. bvb. org.wikibooks.nl

Het CLASSPATH geeft de plaats van de hoofdmap aan. vb. .;C:\programs\java\packages\

  • In windows kan je de waarde van deze variabele instellen via: Deze computer/My computer >Eigenschappen/Properties >Geavanceerd/Advanced >Omgevingsvariabelen/Environment variables; meerdere paden kunnen gecombineerd worden door er een puntkomma tussen te plaatsen.
  • In Linux bevat het opstartscript of het .cshrc-bestand volgend commando: Setenv classpath '.;pad'

.jar[bewerken]

Om zelf een klasse in een samengeperst package, een java archive of kortweg jar te zetten, kunnen we gebruik maken van volgende code (uit te voeren in een DOS-commandoregel):

java -jar programma.jar

De inhoud kan zoals een gewone .zip-file bekeken worden met bvb. WinZip, maar kan er niet mee aangemaakt worden, omdat er naast de .class- en .java-bestanden ook nog een bestand met de naam MANIFEST.MF gemaakt wordt.


Informatie afkomstig van http://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.