Java中內部類和靜態內部類的區別


內部類和靜態內部類

示例

public class OuterClass {
    private int numPrivate = 1;
    public int numPublic = 2;
    public static int numPublicStatic = 3;
    private static int numPrivateStatic = 4;

    public void nonStaticPublicMethod(){
        System.out.println("using nonStaticPublicMethod");
    }

    private void nonStaticPrivateMethod(){
        System.out.println("using nonStaticPrivateMethod");
    }

    public static void staticPublicMethod(){
        System.out.println("using staticPublicMethod");
    }

    private static void staticPrivateMethod(){
        System.out.println("using staticPrivateMethod");
    }

    class InnerClass{

        //Inner class cannot have static declarations
        //static int numInnerClass = 4;
        //public static void test(){}

        int numNonStaticInnerClass = 5;

        public void print(){
            System.out.println("using InnerClass");
            System.out.println("access private field: "+numPrivate);
            System.out.println("access public field: "+numPublic);
            System.out.println("access public static field: "+numPublicStatic);
            System.out.println("access private static field: "+numPrivateStatic);
            System.out.println("access numNonStaticInnerClass: "+numNonStaticInnerClass);
            nonStaticPrivateMethod();
            nonStaticPublicMethod();
            staticPrivateMethod();
            staticPublicMethod();
        }
    }

    static class StaticNestedClass{

        static int numStaticNestedClass = 6;
        int numNonStaticNestedClass = 7;

        public void print(){
            System.out.println("using StaticNestedClass");
            System.out.println("access public static field: "+numPublicStatic);
            System.out.println("access private static field: "+numPrivateStatic);
            System.out.println("access numStaticNestedClass: "+numStaticNestedClass);
            System.out.println("access numNonStaticNestedClass: "+numNonStaticNestedClass);
            staticPrivateMethod();
            staticPublicMethod();
        }
    }

    public static void main(String[] args) {
        //內部類實例對象
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.print();
        System.out.println("=====================");
        //靜態內部類實例化對象
        OuterClass.StaticNestedClass nestedClass = new OuterClass.StaticNestedClass();
        nestedClass.print();
    }
}

結果

using InnerClass
access private field: 1
access public field: 2
access public static field: 3
access private static field: 4
access numNonStaticInnerClass: 5
using nonStaticPrivateMethod
using nonStaticPublicMethod
using staticPrivateMethod
using staticPublicMethod
=====================
using StaticNestedClass
access public static field: 3
access private static field: 4
access numStaticNestedClass: 6
access numNonStaticNestedClass: 7
using staticPrivateMethod
using staticPublicMethod

靜態內部類使用方法

通過外部類訪問靜態內部類

OuterClass.StaticNestedClass

創建靜態內部類對象

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

內部類的使用方法

必須先實例化外部類,才能實例化內部類

OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();

兩者區別

  1. 內部類, 即便是私有的也能訪問,無論靜態還是非靜態都能訪問

    • 可以訪問封閉類(外部類)中所有的成員變量和方法
    • 封閉類(外部類)中的私有private成員變量和方法也可以訪問
    • 內部類中不可以有靜態的變量和靜態的方法
  2. 靜態內部類

    • 無權訪問封閉類(外部類)的中的非靜態變量或者非靜態方法
    • 封閉類(外部類)中的私有private的靜態static成員變量和方法也可以訪問
    • 靜態內部類中可以有靜態的變量和靜態的方法
  3. 內部類可以被聲明為private, public, protected, or package private. 但是封閉類(外部類)只能被聲明為public or package private

特殊情況

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

輸出結果

x = 23
this.x = 1
ShadowTest.this.x = 0

結論

  1. ShadowTest類中定義了三個名字一樣的變量x

    • ShadowTest的成員變量x

    • FirstLevel內部類的成員變量x

    • methodInFirstLevel方法中的參數x

  2. methodInFirstLevel方法中的參數x在內部類FirstLevel的陰影下, 所以在方法methodInFirstLevel中使用x的時候, x指向的是方法的參數x, 此時x的結果為23

  3. 此時this指向的內部類FirstLevel的作用域, 所以this.x的結果是1

  4. ShadowTest.this指向的是ShadowTest的作用域, 此時ShadowTest.this.x的結果是1

為什么使用內部類

  • 這是一種對僅在一個地方使用的類進行邏輯分組的方法:如果一個類僅對另一個類有用,那么將其嵌入該類並將兩者保持在一起是合乎邏輯的。
  • 它增加了封裝:考慮兩個頂級類A和B,其中B需要訪問A的成員,如果將A的成員聲明為private則B無法訪問。通過將類B隱藏在類A中,可以將A的成員聲明為私有,而B可以訪問它們。另外,B本身可以對外界隱藏。
  • 這可能會導致代碼更具可讀性和可維護性:在外部類中嵌套小類會使代碼更靠近使用位置。

序列化

強烈建議不要對內部類(包括 本地和 匿名類)進行序列化。

如果序列化一個內部類,然后使用其他JRE實現對其進行反序列化,則可能會遇到兼容性問題。

Serialization of inner classes, including local and anonymous classes, is strongly discouraged. When the Java compiler compiles certain constructs, such as inner classes, it creates synthetic constructs; these are classes, methods, fields, and other constructs that do not have a corresponding construct in the source code. Synthetic constructs enable Java compilers to implement new Java language features without changes to the JVM. However, synthetic constructs can vary among different Java compiler implementations, which means that .class files can vary among different implementations as well. Consequently, you may have compatibility issues if you serialize an inner class and then deserialize it with a different JRE implementation. See the section Implicit and Synthetic Parameters in the section Obtaining Names of Method Parameters for more information about the synthetic constructs generated when an inner class is compiled.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM