首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 面向對象核心:對象、引用與內部類深度理解

     編輯:Java 相關知識

一、對象與引用:Java 記憶體模型視角

1. 所有東西皆對象(基本型別除外)

Java 中操作對象的句柄是引用,類似 C/C++ 指針但更安全(無指針運算、自動 GC)。

String s;           // 宣告引用,指向 null
s = new String();   // new 在堆上創建對象,返回引用賦給 s
s = "hello";        // 字面量直接賦值,指向常量池/堆對象

關鍵:引用未關聯對象前調用方法會拋 NullPointerException。

2. 記憶體劃分

區域存儲內容特點
棧基本型別變數、對象引用、方法幀線程私有、極快、自動釋放(LIFO)
堆所有對象實例、數組線程共享、GC 管理、分配較慢
方法區類信息、常量、靜態變數、JIT 編譯代碼線程共享、邏輯上屬於堆一部分

基本型別存棧(高頻、小尺寸),對象存堆(生命週期不確定、需 GC)。


二、內部類完整體系

定義在另一個類/方法/代碼塊內部的類,分四類:

1. 成員內部類

class Outer {
    private int outerField = 10;
    class Inner { // 非靜態
        void access() { System.out.println(outerField); } // 可直接訪問外部所有成員
    }
}
// 創建:new Outer().new Inner()
  • 持有外部類引用:Outer.this
  • 可訪問外部類 private 成員
  • 不能定義 static 成員(除非是編譯期常量)

2. 靜態內部類

class Outer {
    static class StaticInner { // static 修飾
        void access() { /* 僅能訪問外部 static 成員 */ }
    }
}
// 創建:new Outer.StaticInner() — 無需外部實例
  • 不持有外部類引用,獨立存在
  • 常用於:Builder 模式、單例持有者、工具類分組

3. 方法局部內部類

class Outer {
    void method() {
        final int localVar = 10; // Java 8+ 可省略 final(effectively final)
        class LocalInner {
            void print() { System.out.println(localVar); }
        }
        new LocalInner().print();
    }
}
  • 僅在方法內可見,編譯後生成 Outer$1LocalInner.class
  • 只能訪問 final 或 effectively final 的局部變數
  • 不能有訪問修飾符,不能 static

4. 匿名內部類

Runnable r = new Runnable() { // 實現接口
    @Override public void run() { System.out.println("匿名類"); }
};

Comparator cmp = new Comparator<>() { // Java 9+ 鑽石操作符
    @Override public int compare(String a, String b) { return a.length() - b.length(); }
};
  • 無名、不可復用、單次使用
  • 常用於:事件監聽、線程任務、策略模式臨時實現
  • 同樣只能捕獲 final/effectively final 變數

三、內部類的兩大核心價值

1. 封裝與隱藏實現細節

public class Goods {
    // 內部類對外不可見,完美隱藏
    private class ContentImpl implements Content { ... }
    private class DestinationImpl implements Destination { ... }
    
    public Content getContent() { return new ContentImpl(); }
    public Destination getDestination(String label) { return new DestinationImpl(label); }
}

外部只見介面 Content、Destination,不知具體實現類,降低耦合。

2. 實現「多實現」效果(彌補無多重繼承)

public class Outer {
    // 每個內部類可獨立實現不同介面/繼承不同類
    class ImplA implements InterfaceA { ... }
    class ImplB extends AbstractB { ... }
    class ImplC implements InterfaceC { ... }
    
    // 對外提供多種能力
    public InterfaceA getA() { return new ImplA(); }
    public AbstractB getB() { return new ImplB(); }
}

一個外部類實例可產出多種型別的內部實例,實現邏輯上的「多重繼承」。


四、經典案例:迭代器模式

public class MyList implements Iterable {
    private Node head;
    
    @Override public Iterator iterator() {
        return new Iterator() { // 匿名內部類實現 Iterator
            Node current = head;
            @Override public boolean hasNext() { return current != null; }
            @Override public E next() {
                E val = current.val;
                current = current.next;
                return val;
            }
        };
    }
    
    private static class Node { // 靜態內部類:節點結構
        E val; Node next;
    }
}
  • Node 為靜態內部類:不依賴外部實例,純數據結構。
  • Iterator 為匿名內部類:捕獲 head 引用,實現遍歷邏輯。

五、最佳實踐指南

  1. 默認使用 static 內部類,除非確實需要訪問外部實例成員。
  2. 匿名內部類邏輯超過 10 行考慮提取為具名類(Lambda 表達式可替代函數式介面)。
  3. 局部內部類極少用,通常用 Lambda 或方法引用替代。
  4. 內部類序列化需謹慎:會隱式序列化外部類引用,導致 NotSerializableException。
  5. 避免在內部類中大量捕獲外部變數,增加記憶體洩漏風險(特別是非靜態內部類持有外部類引用)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved