Java內部類別是定義在另一個類別的內部。Java內部類別可以被聲明為private、public、protected或預設存取,而外部類別只能有public或預設存取。Java嵌套類別分為兩種類型。
-
靜態嵌套類別
如果嵌套類別是靜態的,則稱為靜態嵌套類別。靜態嵌套類別只能訪問外部類別的靜態成員。靜態嵌套類別與任何其他頂層類別相同,只是為了方便封裝而嵌套。可以使用以下語句創建靜態類別物件。
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
-
java 內部類別
在 Java 中,任何非靜態嵌套類別都被稱為內部類別。Java 內部類別與該類別的物件相關聯,它們可以訪問外部類別的所有變數和方法。由於內部類別與實例相關聯,因此無法在其中使用任何靜態變數。Java 內部類別的物件是外部類別物件的一部分,要創建內部類別的實例,我們首先需要創建外部類別的實例。Java 內部類別可以像這樣實例化;
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Java 內部類別有兩種特殊類型。
-
本地內部類別
如果類別在方法內部被定義,則稱為本地內部類別。由於本地內部類別與物件無關,因此無法使用private、public或protected訪問修飾符。唯一允許的修飾符是abstract或final。本地內部類別可以訪問封閉類別和定義範圍內的本地final變數的所有成員。此外,它還可以訪問所在方法的非final本地變數,但無法修改它們。因此,如果嘗試在方法內部類別中更改非final本地變數的值,將獲得編譯時錯誤。本地內部類別的定義方式如下:
package com.journaldev.innerclasses; public class MainClass { private String s_main_class; public void print() { String s_print_method = ""; // 方法內的本地內部類別 class Logger { // 能夠訪問封閉類別變數 String name = s_main_class; // 能夠訪問非final方法變數 String name1 = s_print_method; public void foo() { String name1 = s_print_method; // 以下代碼將引發編譯時錯誤: // 在封閉範圍中定義的本地變數s_print_method必須是final或有效final的 // s_print_method= ":"; } } // 在方法中實例化本地內部類別以使用 Logger logger = new Logger(); } }
我們也可以在任何區塊內定義本地內部類別,例如靜態區塊、if-else區塊等。然而,在這種情況下,類別的範圍將非常有限。
public class MainClass { static { class Foo { } Foo f = new Foo(); } public void bar() { if(1 < 2) { class Test { } Test t1 = new Test(); } // 以下將引發錯誤,因為類別的範圍有限 //Test t = new Test(); //Foo f = new Foo(); } }
-
匿名內部類別
沒有名稱的區域內部類別被稱為匿名內部類別。匿名類別在定義和實例化時是一個單一的陳述句。匿名內部類別必定是繼承一個類別或實作一個介面。由於匿名內部類別沒有名稱,所以無法為其定義建構子。匿名內部類別只能在定義的地方存取。如何建立匿名內部類別的方式有點難以定義,我們將在下面的測試程式中看到它的實際用途。
以下是一個 Java 類別示範如何定義 Java 內部類別、靜態巢狀類別、區域內部類別和匿名內部類別的程式碼:OuterClass.java
package com.journaldev.nested;
import java.io.File;
import java.io.FilenameFilter;
public class OuterClass {
private static String name = "OuterClass";
private int i;
protected int j;
int k;
public int l;
//OuterClass 建構子
public OuterClass(int i, int j, int k, int l) {
this.i = i;
this.j = j;
this.k = k;
this.l = l;
}
public int getI() {
return this.i;
}
//靜態巢狀類別,可以存取 OuterClass 的靜態變數/方法
static class StaticNestedClass {
private int a;
protected int b;
int c;
public int d;
public int getA() {
return this.a;
}
public String getName() {
return name;
}
}
//內部類別,非靜態且可以存取外部類別的所有變數/方法
class InnerClass {
private int w;
protected int x;
int y;
public int z;
public int getW() {
return this.w;
}
public void setValues() {
this.w = i;
this.x = j;
this.y = k;
this.z = l;
}
@Override
public String toString() {
return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z;
}
public String getName() {
return name;
}
}
//區域內部類別
public void print(String initial) {
//區域內部類別 inside the method
class Logger {
String name;
public Logger(String name) {
this.name = name;
}
public void log(String str) {
System.out.println(this.name + ": " + str);
}
}
Logger logger = new Logger(initial);
logger.log(name);
logger.log("" + this.i);
logger.log("" + this.j);
logger.log("" + this.k);
logger.log("" + this.l);
}
//匿名內部類別
public String[] getFilesInDir(String dir, final String ext) {
File file = new File(dir);
//匿名內部類別 implementing FilenameFilter interface
String[] filesList = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(ext);
}
});
return filesList;
}
}
這裡是展示如何在 Java 中實例化和使用內部類別的測試程式。 InnerClassTest.java
package com.journaldev.nested;
import java.util.Arrays;
//巢狀類別可在 import 中使用,以方便實例化
import com.journaldev.nested.OuterClass.InnerClass;
import com.journaldev.nested.OuterClass.StaticNestedClass;
public class InnerClassTest {
public static void main(String[] args) {
OuterClass outer = new OuterClass(1,2,3,4);
//靜態巢狀類別範例
StaticNestedClass staticNestedClass = new StaticNestedClass();
StaticNestedClass staticNestedClass1 = new StaticNestedClass();
System.out.println(staticNestedClass.getName());
staticNestedClass.d=10;
System.out.println(staticNestedClass.d);
System.out.println(staticNestedClass1.d);
//內部類別範例
InnerClass innerClass = outer.new InnerClass();
System.out.println(innerClass.getName());
System.out.println(innerClass);
innerClass.setValues();
System.out.println(innerClass);
//使用區域內部類別呼叫方法
outer.print("Outer");
//使用匿名內部類別呼叫方法
System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
}
}
這裡是上述 Java 內部類別範例程式的輸出。
OuterClass
10
0
OuterClass
w=0:x=0:y=0:z=0
w=1:x=2:y=3:z=4
Outer: OuterClass
Outer: 1
Outer: 2
Outer: 3
Outer: 4
[NestedClassTest.java, OuterClass.java]
[NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class]
請注意,當 OuterClass 編譯時,內部類別、區域內部類別和靜態巢狀類別會分別建立獨立的類別檔案。
Java 內部類別的好處
- 如果一個類別僅對一個類別有用,將其嵌套在一起是有意義的。這有助於封裝類別。
- Java 內部類別實現了封裝。請注意,內部類別可以訪問外部類別的私有成員,同時我們可以隱藏內部類別不讓外界訪問。
- 將小類別放在頂層類別內部可以使代碼更接近使用的地方,並使代碼更易讀和維護。
這就是關於 Java 內部類別的全部內容。
Source:
https://www.digitalocean.com/community/tutorials/java-inner-class