[Java] 4 types of Java inner classes

Java中有四種inner class,分別是:

  1. static inner class
  2. member inner Class
  3. local inner class
  4. anonymous inner class

Static inner class:

1
2
3
4
5
6
7
8
9
10
11
12
public class OutterClass {
public static class InnerClass {
public void print() {
System.out.println("I am a static inner class");
}
}

public static void main(String[] args) {
OutterClass.InnerClass innerClass = new OutterClass.InnerClass();
innerClass.print();
}
}

static inner class不能存取outter class的memeber或method!若是一定要存取,則memeber或method要用static修飾。

Member inner Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class OutterClass {
private int x = 0;
private InnerClass innerClass;

public OutterClass() {
innerClass = new InnerClass();
}

private class InnerClass {
private void print() {
x = x++;
System.out.println("Outer x is " + x);
}
}

public void print() {
innerClass.print();
}

public static void main(String[] args) {
OutterClass outterClass = new OutterClass();
outterClass.print();
}
}
  1. inner class可以自由存取outter class的member或method。
  2. 通常會用private修飾inner class,這樣可以避免公佈太多的細節,違反封裝原則。

    Local inner class:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class OutterClass {
    private int x = 0;

    public void print() {
    final int y = 10;
    class InnerClass implements Runnable {
    @Override
    public void run() {
    while (true) {
    System.out.println("The value of x in OutterClass is " + x);
    System.out.println("The value of y in print() is " + y);

    try {
    Thread.sleep(1000);
    }
    catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }

    }

    new Thread(new InnerClass()).start();
    }

    public static void main(String[] args) {
    OutterClass outterClass = new OutterClass();
    outterClass.print();
    }
    }
  3. inner class可以自由存取outter class的member和method。

  4. inner class要存取所在method的變數,必須使用final修飾該變數。
    原因:以上述例子為例,當呼叫到outterClass.print(),變數y就失去作用了。然而InnerClass要再存取y就會出錯,所以才會使用final修飾變數y。即複製一份變數y給InnerClass使用,且值都不會再改變。Java 8有支援Closure就可以解決此問題。

    Anonymous inner class:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static void main(String[] args) {
    new Runnable() {
    @Override
    public void run() {
    System.out.println("I am a anonymous class");

    }
    };
    }

性質和local inner class相同。


如果多個變數為相同名稱時,預設會選用距離inner class最近的變數。不過實務上開發者很少會把變數名稱取為相同,有可能會讓讀者困惑。請參考Shadowing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
}
}

結果:

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

參考資料: