class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Ezeket a belső osztályokat beágyazottnak nevezzük. 2 típusra oszthatók:
- Nem statikus beágyazott osztályok. Ezeket belső osztályoknak is nevezik.
- Statikus beágyazott osztályok.
- egy helyi osztály
- egy névtelen osztály

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!");
}
}
}
Itt van az Bicycle
osztály. 2 mezője és 1 metódusa van: start()
. 
Handlebar
és Seat
. A kódjuk az osztályon belül van írva Bicycle
. Ezek teljes értékű osztályok: mint látható, mindegyiknek megvan a maga módszere. Ezen a ponton felmerülhet a kérdés: mi a fenéért helyeznénk el egyik osztályt a másikba? Miért kell őket belső osztályokká tenni? Nos, tegyük fel, hogy külön osztályokra van szükségünk a programunkban a kormány és az ülés fogalmához. Természetesen nem szükséges, hogy beágyazzuk őket! Készíthetünk rendes órákat. Például így:
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!");
}
}
Nagyon jó kérdés! Természetesen nem korlátoz minket a technológia. Ez természetesen egy lehetőség. Itt inkább az órák helyes kialakítása az adott program és annak célja szempontjából a fontos. A belső osztályok egy olyan entitás elkülönítésére szolgálnak, amely elválaszthatatlanul kapcsolódik egy másik entitáshoz. A kormány, az ülések és a pedálok a kerékpár részei. A biciklitől elválasztva nincs sok értelmük. Ha ezeket a fogalmakat külön nyilvános osztályokká tesszük, akkor a programunkban a következő kódot kaptuk volna:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
Hmm... Ennek a kódnak a jelentését még nehéz megmagyarázni. Van egy bizonytalan kormányunk (miért van rá szükség? Fogalmam sincs, hogy őszinte legyek). És ez a fogantyú jobbra fordul... magától, bicikli nélkül... valamiért. A kormány és a kerékpár fogalmának elválasztásával némi logikát veszítettünk programunkból. Egy belső osztály használatával a kód nagyon eltérően néz ki:
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();
}
}
Konzol kimenet:
Seat up!
Let's go!
Steer left!
Steer right!
Most, amit látunk, hirtelen értelmet nyer! :) Bicikli objektumot alkottunk. Létrehoztunk két kerékpáros "altárgyat" - egy kormányt és egy ülést. Felemeltük az ülést a kényelem kedvéért, és indultunk is: pedálozunk és kormányozunk, ahogy kellett! :) A szükséges metódusokat a megfelelő objektumokon hívjuk meg. Mindez egyszerű és kényelmes. Ebben a példában a kormány és az ülés szétválasztása javítja a tokozást (az adott osztályon belül elrejti a kerékpáralkatrészek adatait), és lehetővé teszi egy részletesebb absztrakció létrehozását. Most nézzünk egy másik helyzetet. Tegyük fel, hogy szeretnénk létrehozni egy programot, amely szimulál egy kerékpárboltot és a kerékpárok alkatrészeit. 
-
Egy belső osztály objektuma nem létezhet egy külső osztály objektuma nélkül.
Ez logikus: ezért készítettük el programunkban a
Seat
és a belső osztályokat – hogy ne kerüljön elárvult kormány és ülés.Handlebar
Ez a kód nem fordítja le:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
Ebből egy másik fontos jellemző következik:
-
Egy belső osztály objektuma hozzáfér a külső osztály változóihoz.
Például adjunk hozzá egy
int seatPostDiameter
változót (amely a nyeregcső átmérőjét jelenti) az osztályunkhozBicycle
.Ezután a
Seat
belső osztályban létrehozhatunk egydisplaySeatProperties()
metódust, amely megjeleníti az ülés tulajdonságait: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); } } }
És most ezt az információt megjeleníthetjük a programunkban:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
Konzol kimenet:
Seat properties: seatpost diameter = 40
Jegyzet:az új változót a legszigorúbb hozzáférésmódosítóval (
private
) deklaráljuk. És még mindig a belső osztálynak van hozzáférése! -
Egy belső osztály objektuma nem hozható létre egy külső osztály statikus metódusában.
Ezt a belső osztályok megszervezésének sajátosságai magyarázzák. Egy belső osztály rendelkezhet paraméterekkel rendelkező konstruktorokkal, vagy csak az alapértelmezett konstruktorral. De ettől függetlenül, amikor létrehozunk egy belső osztály objektumát, a külső osztály objektumára való hivatkozás láthatatlanul átkerül a belső osztály létrehozott objektumához. Hiszen egy ilyen tárgyreferencia megléte abszolút követelmény. Ellenkező esetben nem tudjuk létrehozni a belső osztály objektumait.
De ha a külső osztály metódusa statikus, akkor lehet, hogy nem lesz a külső osztály objektuma! És ez sértené a belső osztály működésének logikáját. Ebben a helyzetben a fordító hibát generál:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Egy belső osztály nem tartalmazhat statikus változókat és metódusokat.
A logika ugyanaz: statikus metódusok és változók létezhetnek, és objektum hiányában is hívhatók vagy hivatkozhatnak rájuk.
De a külső osztály objektuma nélkül nem lesz hozzáférésünk a belső osztályhoz.
Egyértelmű ellentmondás! Ez az oka annak, hogy a statikus változók és metódusok nem megengedettek a belső osztályokban.
A fordító hibát generál, ha megpróbálja létrehozni őket:
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); } } }
-
Egy belső osztály objektumának létrehozásakor fontos a hozzáférés módosítója.
Egy belső osztályt a standard hozzáférés módosítókkal lehet megjelölni:
public
,private
,protected
, éspackage private
.Miért számít ez?
Ez befolyásolja, hogy a programunkban hol hozhatunk létre példányokat a belső osztályból.
Ha az
Seat
osztályunk a következővel van deklarálva , akkor bármely más osztálybanpublic
létrehozhatunk objektumokat.Seat
Az egyetlen követelmény az, hogy a külső osztály objektumának is léteznie kell.Egyébként ezt már megtettük itt:
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(); } }
Az osztályból könnyen bejutottunk a
Handlebar
belső osztálybaMain
.Ha a belső osztályt -nak deklaráljuk
private
, akkor csak a külső osztályon belül tudunk objektumokat létrehozni.Seat
"Kívülről" már nem tudunk objektumot létrehozni :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(); } }
Valószínűleg már érted a logikát :)
-
A belső osztályokhoz tartozó hozzáférés-módosítók ugyanúgy működnek, mint a közönséges változók esetében.
A
protected
módosító hozzáférést biztosít egy példányváltozóhoz azokban az alosztályokban és osztályokban, amelyek ugyanabban a csomagban vannak.protected
belső osztályokra is működik. Létrehozhatunkprotected
objektumokat a belső osztályból:- a külső osztályban;
- alosztályaiban;
- osztályokban, amelyek ugyanabban a csomagban vannak.
Ha a belső osztály nem rendelkezik hozzáférésmódosítóval (
package private
), akkor a belső osztály objektumai létrehozhatók:- a külső osztályban;
- osztályokban, amelyek ugyanabban a csomagban vannak.
Régóta ismeri a módosítókat, így nincs probléma.
GO TO FULL VERSION