class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Deze interne klassen worden genest genoemd. Ze zijn onderverdeeld in 2 soorten:
- Niet-statische geneste klassen. Dit worden ook wel innerlijke klassen genoemd.
- Statische geneste klassen.
- een lokale klas
- een anonieme klas

public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Hier hebben we de Bicycle
klas. Het heeft 2 velden en 1 methode: start()
. 
Handlebar
en Seat
. Hun code is in de klas geschreven Bicycle
. Dit zijn volwaardige klassen: zoals u kunt zien, heeft elk van hen zijn eigen methoden. Op dit punt heb je misschien een vraag: waarom zouden we in vredesnaam de ene klas in de andere plaatsen? Waarom zouden ze innerlijke klassen maken? Stel dat we aparte lessen nodig hebben voor de concepten stuur en zadel in ons programma. Het is natuurlijk niet nodig dat we ze genest maken! We kunnen gewone klassen maken. Bijvoorbeeld als volgt:
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Zeer goede vraag! Natuurlijk worden we niet beperkt door de technologie. Dat doen is zeker een optie. Hier gaat het meer om het juiste ontwerp van de klassen vanuit het perspectief van een specifiek programma en het doel ervan. Innerlijke klassen zijn voor het scheiden van een entiteit die onlosmakelijk verbonden is met een andere entiteit. Stuur, zadels en pedalen zijn onderdelen van een fiets. Los van de fiets hebben ze weinig zin. Als we van al deze concepten afzonderlijke openbare klassen zouden maken, zouden we de volgende code in ons programma hebben gehad:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
Hmm... De betekenis van deze code is zelfs moeilijk uit te leggen. We hebben een vaag stuur (waarom is het nodig? Geen idee, om eerlijk te zijn). En deze hendel draait naar rechts... helemaal vanzelf, zonder fiets... om de een of andere reden. Door het concept van het stuur te scheiden van het concept van de fiets, verloren we enige logica in ons programma. Met behulp van een innerlijke klasse ziet de code er heel anders uit:
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.Handlebar handlebar = peugeot.new Handlebar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handlebar.left();
handlebar.right();
}
}
Console-uitvoer:
Seat up!
Let's go!
Steer left!
Steer right!
Nu is wat we zien ineens logisch! :) We hebben een fietsobject gemaakt. We hebben twee "subobjecten" voor fietsen gemaakt: een stuur en een stoel. We verhoogden de stoel voor comfort en daar gingen we: trappen en sturen als dat nodig was! :) De methoden die we nodig hebben, worden aangeroepen op de juiste objecten. Het is allemaal eenvoudig en handig. In dit voorbeeld verbetert het scheiden van het stuur en het zadel de inkapseling (we verbergen gegevens over de fietsonderdelen binnen de relevante klasse) en stelt ons in staat een meer gedetailleerde abstractie te creëren. Laten we nu eens naar een andere situatie kijken. Stel dat we een programma willen maken dat een fietsenwinkel en reserveonderdelen voor fietsen simuleert. 
-
Een object van een binnenklasse kan niet bestaan zonder een object van een buitenklasse.
Dit is logisch: daarom hebben we de
Seat
enHandlebar
innerlijke klassen in ons programma opgenomen - zodat we niet eindigen met verweesde sturen en stoelen.Deze code compileert niet:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
Hieruit volgt nog een belangrijk kenmerk:
-
Een object van een binnenklasse heeft toegang tot de variabelen van de buitenklasse.
Laten we bijvoorbeeld een
int seatPostDiameter
variabele (die de diameter van de zadelpen vertegenwoordigt) aan onzeBicycle
klas toevoegen.Vervolgens
Seat
kunnen we in de innerlijke klasse eendisplaySeatProperties()
methode maken die de stoeleigenschappen weergeeft:public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
En nu kunnen we deze informatie weergeven in ons programma:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
Console-uitvoer:
Seat properties: seatpost diameter = 40
Opmerking:de nieuwe variabele wordt gedeclareerd met de strengste toegangsmodificator (
private
). En toch heeft de binnenklas toegang! -
Een object van een binnenklasse kan niet worden gemaakt in een statische methode van een buitenklasse.
Dit wordt verklaard door de specifieke kenmerken van hoe innerlijke klassen zijn georganiseerd. Een binnenklasse kan constructors met parameters hebben, of alleen de standaardconstructor. Maar hoe dan ook, wanneer we een object van een binnenste klasse creëren, wordt een verwijzing naar het object van de buitenste klasse onzichtbaar doorgegeven aan het gecreëerde object van de binnenste klasse. De aanwezigheid van zo'n objectreferentie is immers een absolute vereiste. Anders kunnen we geen objecten van de innerlijke klasse maken.
Maar als een methode van de buitenste klasse statisch is, dan hebben we misschien geen object van de buitenste klasse! En dit zou een schending zijn van de logica van hoe een innerlijke klasse werkt. In deze situatie genereert de compiler een fout:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Een binnenklasse kan geen statische variabelen en methoden bevatten.
De logica is hetzelfde: statische methoden en variabelen kunnen bestaan en kunnen worden aangeroepen of waarnaar wordt verwezen, zelfs als er geen object is.
Maar zonder een object van de buitenste klasse hebben we geen toegang tot de binnenste klasse.
Een duidelijke tegenstelling! Dit is de reden waarom statische variabelen en methoden niet zijn toegestaan in innerlijke klassen.
De compiler genereert een foutmelding als u ze probeert te maken:
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
Bij het maken van een object van een innerlijke klasse is de toegangsmodificator belangrijk.
Een binnenklasse kan worden gemarkeerd met de standaard toegangsmodificaties:
public
,private
,protected
, enpackage private
.Waarom is dit van belang?
Dit beïnvloedt waar we instanties van de innerlijke klasse in ons programma kunnen maken.
Als onze
Seat
klasse is gedeclareerd alspublic
, kunnen weSeat
objecten in elke andere klasse maken. De enige vereiste is dat er ook een object van de buitenste klasse moet bestaan.Dat hebben we hier trouwens al gedaan:
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.Handlebar handlebar = peugeot.new Handlebar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handlebar.left(); handlebar.right(); } }
We kregen gemakkelijk toegang tot de
Handlebar
binnenste klas van deMain
klas.Als we de innerlijke klasse declareren als
private
, kunnen we alleen objecten maken binnen de buitenste klasse.Seat
We kunnen niet langer een object "aan de buitenkant" maken :private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
Je begrijpt de logica waarschijnlijk al :)
-
Toegangsmodificatoren voor interne klassen werken hetzelfde als voor gewone variabelen.
De
protected
modifier geeft toegang tot een instantievariabele in subklassen en klassen die zich in hetzelfde pakket bevinden.protected
werkt ook voor innerlijke klassen. We kunnenprotected
objecten van de innerlijke klasse maken:- in de buitenste klasse;
- in zijn subklassen;
- in lessen die in hetzelfde pakket zitten.
Als de binnenklasse geen toegangsmodificator (
package private
) heeft, kunnen objecten van de binnenklasse worden gemaakt:- in de buitenste klasse;
- in lessen die in hetzelfde pakket zitten.
U bent al lang bekend met modifiers, dus geen problemen hier.
GO TO FULL VERSION