在一個類內部定義另一個類,即為內部類。編譯後產生獨立 .class 檔案,命名規則:外部類$內部類.class(如 Outer$Inner.class)。
| 類型 | 定義位置 | 訪問外部成員 | 實例化方式 | 典型場景 |
|---|---|---|---|---|
| 成員內部類 | 類體中、方法外 | 直接訪問所有 (含 private) | new Outer().new Inner() | 邏輯強綁定、需頻繁訪問外部狀態 |
| 靜態嵌套類 | 類體中、static 修飾 | 僅訪問 static 成員 | new Outer.Nested() | 工具類、Builder 模式、不依賴外部實例 |
| 局部內部類 | 方法/代碼塊內 | 訪問 final/實際不可變區域變數 | 方法內 new Local() | 複雜演算法封裝、一次性邏輯 |
| 匿名內部類 | 表達式中、無類名 | 同局部內部類 | new Interface() { ... } | 事件監聽、回調、策略模式臨時實現 |
public class Outer {
private int outerField = 10;
class Inner {
private int innerField = 20;
public void print() {
System.out.println("內部類字段: " + innerField); // 20
System.out.println("外部類字段: " + outerField); // 10
System.out.println("外部類字段(顯式): " + Outer.this.outerField); // 10
}
}
// 方式1:外部類方法創建內部實例
public void createInner() {
Inner inner = new Inner();
inner.print();
}
}
// 方式2:外部類直接實例化
public class Main {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.print();
}
}
Outer.this.field 顯式訪問外部private 時,僅外部類能實例化 (方式1)static 非 final 字段 → 必須宣告為 static class (即靜態嵌套類)public class Outer {
public void method() {
final int localVar = 30; // Java 8+ 可省略 final,但必須「實際不可變」
class Local {
public void print() {
System.out.println("捕獲局部變數: " + localVar); // 30
}
}
new Local().print();
// localVar = 40; // 編譯錯誤:被內部類捕獲後不可修改
}
}
原理:編譯器將捕獲的局部變數值複製到內部類實例隱藏字段,延長生命週期。若允許修改,副本與原值不一致違反語義。
// 1. 基於抽象類
abstract class Animal {
public abstract void run();
public abstract void sleep();
}
public class Demo {
public void test() {
Animal dog = new Animal() { // 匿名子類
@Override public void run() { System.out.println("狗在跑"); }
@Override public void sleep() { System.out.println("狗在睡"); }
};
dog.run();
}
// 2. 基於介面 - 線程任務
public void threadDemo() {
Runnable task = new Runnable() {
@Override public void run() { System.out.println("異步任務執行"); }
};
new Thread(task).start();
}
// 3. 策略模式臨時實現
public void sortDemo() {
List list = Arrays.asList("c", "a", "b");
list.sort(new Comparator() {
@Override public int compare(String o1, String o2) {
return o2.compareTo(o1); // 降序
}
});
}
}
class Task implements Runnable {
public void run() {
System.out.println("this (Runnable實例): " + this); // Task@hash
System.out.println("Thread.currentThread(): " + Thread.currentThread()); // Thread[Thread-0,5,main]
}
}
new Thread(new Task()).start();
this:指向實現類實例 (Runnable 物件)Thread.currentThread():指向正在執行代碼的線程對象| 方法類型 | 同步鎖對象 | 同步範圍 |
|---|---|---|
非靜態 synchronized void m() | this (當前實例) | 同一實例的所有非靜態同步方法互斥 |
靜態 synchronized static void m() | ClassName.class (Class 對象) | 全類所有靜態同步方法互斥 |
同步塊 synchronized(obj) | obj (任意對象) | 自定義鎖粒度 |
public class Singleton {
// volatile 禁止指令重排,保證可見性
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查:無鎖,高效
synchronized (Singleton.class) { // 類級鎖
if (instance == null) { // 第二次檢查:防重複創建
instance = new Singleton();
}
}
}
return instance;
}
}
關鍵點:volatile 確保 instance = new Singleton() (分配內存→初始化→賦值引用) 不被重排序,避免其他線程看到半初始化對象。
synchronized(lockA), synchronized(lockB))wait()/notify() 必須由持有該鎖的線程在同步塊內呼叫notify(),故定義在 Object 通用已棄用:stop()、suspend()、resume() (破壞鎖一致性、導致死鎖/數據損壞)
public class Worker implements Runnable {
private volatile boolean running = true;
public void run() {
while (running && !Thread.currentThread().isInterrupted()) {
try {
// 業務邏輯
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// 睡眠/等待被中斷 → 清除中斷標誌 → 手動重設或退出
Thread.currentThread().interrupt(); // 重設標誌供上層檢查
break;
}
}
}
public void shutdown() { running = false; }
}
// 使用
Worker worker = new Worker();
Thread t = new Thread(worker);
t.start();
// ... 稍後停止
worker.shutdown(); // 正常退出標誌
t.interrupt(); // 強制中斷阻塞操作
t.join(); // 等待結束
| 方法 | 屬性 | 行為 | 中斷標誌 |
|---|---|---|---|
interrupt() | 實例 | 設置中斷標誌;若線程阻塞於 sleep/wait/join → 拋出 InterruptedException 並清除標誌 | 設置/清除後重設 |
isInterrupted() | 實例 | 檢查標誌,不清除 | 只讀 |
interrupted() | static | 檢查當前線程標誌並清除 | 讀取並清除 |
// 替代 synchronized + wait/notify
Lock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 生產者
lock.lock();
try {
while (queue.size() == capacity) notFull.await(); // 精確喚醒
queue.add(item);
notEmpty.signal(); // 只喚醒消費者
} finally { lock.unlock(); }
// 消費者
lock.lock();
try {
while (queue.isEmpty()) notEmpty.await();
Item item = queue.poll();
notFull.signal(); // 只喚醒生產者
return item;
} finally { lock.unlock(); }
優勢:多條件變量精確喚醒 (避免 notifyAll 驚群)、可中斷鎖獲取 (lockInterruptibly)、公平鎖選項、嘗試非阻塞獲取 (tryLock)。