class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
這些內部類被稱為嵌套。它們分為兩種類型:
- 非靜態嵌套類。這些也稱為內部類。
- 靜態嵌套類。
- 本地班級
- 匿名類

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!");
}
}
}
我們在這裡上課Bicycle
。它有 2 個字段和 1 個方法:start()
. 
Handlebar
和Seat
。他們的代碼寫在Bicycle
類裡面。這些是成熟的類:如您所見,每個類都有自己的方法。說到這裡,您可能會有一個疑問:為什麼我們要把一個類放在另一個類中?為什麼要讓它們成為內部類?好吧,假設我們需要單獨的類來處理程序中的把手和座椅的概念。當然,我們沒有必要讓它們嵌套!我們可以做普通班。例如,像這樣:
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!");
}
}
很好的問題!當然,我們不受技術的限制。這樣做當然是一種選擇。在這裡,更重要的是從特定程序及其目的的角度正確設計類。內部類用於分離出與另一個實體密不可分的實體。車把、車座和踏板是自行車的組成部分。與自行車分開,它們沒有多大意義。如果我們將所有這些概念單獨的公共類,我們的程序中就會有這樣的代碼:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
嗯……這段代碼的意思就更難解釋了。我們有一些模糊的車把(為什麼有必要?老實說,不知道)。這個把手向右轉……完全靠自己,沒有自行車……出於某種原因。通過將車把的概念與自行車的概念分開,我們在程序中丟失了一些邏輯。使用內部類,代碼看起來非常不同:
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();
}
}
控制台輸出:
Seat up!
Let's go!
Steer left!
Steer right!
現在我們所看到的突然變得有道理了!:) 我們創建了一個自行車對象。我們創建了兩個自行車“子對象”——一個把手和一個座椅。為了舒適起見,我們將座椅抬高,然後出發:根據需要踩踏板和轉向!:) 我們需要的方法在適當的對像上被調用。一切都簡單方便。在此示例中,將車把和座椅分開可增強封裝(我們將有關自行車零件的數據隱藏在相關類中)並讓我們創建更詳細的抽象。現在讓我們看看不同的情況。假設我們要創建一個模擬自行車商店和自行車備件的程序。 
-
沒有外部類的對象,內部類的對象就不能存在。
這是有道理的:這就是我們在程序中創建內部類
Seat
和Handlebar
內部類的原因——這樣我們就不會得到孤立的車把和座椅。此代碼無法編譯:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
另一個重要特徵由此而來:
-
內部類的對象可以訪問外部類的變量。
例如,讓我們
int seatPostDiameter
在我們的類中添加一個變量(代表座桿的直徑)Bicycle
。然後在
Seat
內部類中,我們可以創建一個displaySeatProperties()
顯示座位屬性的方法: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); } } }
現在我們可以在我們的程序中顯示這些信息:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
控制台輸出:
Seat properties: seatpost diameter = 40
筆記:新變量使用最嚴格的訪問修飾符 ( ) 聲明
private
。而且內部類仍然可以訪問! -
不能在外部類的靜態方法中創建內部類的對象。
這可以通過內部類的組織方式的具體特徵來解釋。內部類可以有帶參數的構造函數,或者只有默認構造函數。但無論如何,當我們創建一個內部類的對象時,外部類對象的引用無形中傳遞給了內部類創建的對象。畢竟,存在這樣一個對象引用是絕對必要的。否則,我們將無法創建內部類的對象。
但是如果外部類的方法是靜態的,那麼我們可能沒有外部類的對象!這將違反內部類如何工作的邏輯。在這種情況下,編譯器會產生一個錯誤:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
內部類不能包含靜態變量和方法。
邏輯是一樣的:即使沒有對象,靜態方法和變量也可以存在並被調用或引用。
但是如果沒有外部類的對象,我們將無法訪問內部類。
明顯的矛盾!這就是內部類中不允許使用靜態變量和方法的原因。
如果您嘗試創建它們,編譯器將生成錯誤:
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); } } }
-
創建內部類的對象時,其訪問修飾符很重要。
可以使用標準訪問修飾符標記內部類:
public
、private
、protected
和package private
。為什麼這很重要?
這會影響我們可以在程序中創建內部類實例的位置。
如果我們的
Seat
類聲明為public
,我們可以在任何其他類中創建Seat
對象。唯一的要求是外部類的對像也必須存在。順便說一句,我們已經在這裡做了:
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(); } }
我們很容易
Handlebar
從Main
類中獲得了對內部類的訪問權。如果我們將內部類聲明為
private
,我們將只能在外部類中創建對象。我們不能再
Seat
“在外面”創建一個對象: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(); } }
您可能已經理解其中的邏輯 :)
-
內部類的訪問修飾符與普通變量的工作方式相同。
修飾符
protected
提供對同一包中的子類和類中的實例變量的訪問。protected
也適用於內部類。我們可以創建protected
內部類的對象:- 在外部類;
- 在其子類中;
- 在同一個包中的類中。
如果內部類沒有訪問修飾符(
package private
),則可以創建內部類的對象:- 在外部類;
- 在同一個包中的類中。
您已經熟悉修飾符很長時間了,所以這裡沒有問題。
GO TO FULL VERSION