內部類別
內部類別Inner class
在一個類別中,宣告一個類別,這個類別就是內部類。
外部類別Outer Class
包含內部類別的類別稱為外部類別。
1
2
3
4
5
public class Outter { //外部類別
public class Inner{ // 內部類別
}
}
建立new內部類別
- 先建立外部類別物件
- 建立方式如下
外部類別物件變數.new 內部類別()
1
2
3
4
5
6
7
8
9
10
11
12
public class Outter { //外部類別
public class Inner{ // 內部類別
}
public static void main(String[] args) {
// 建立外部類別
Outter outter = new Outter();
// 再建立內部類別
Inner inner = outter.new Inner();
}
}
內部類別建構子
1
2
3
4
5
6
7
8
9
10
11
12
public class Outter { //外部類別
public class Inner{
Inner() {
System.out.println("內部類建構子");
}
}
public static void main(String[] args) {
// 建立內部類別
Outter outter = new Outter();
Inner inner = outter.new Inner();
}
}
內部類建構子
存取外部類別的成員變數與成員方法
外部類別的成員變數、成員方法、靜態變數、靜態方法,在內部類別是可以存取。
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 Outter {
private String name = "Outter";
private static String staticval = "Static val";
private static void staticMethod() {
System.out.println("outterstatic method");
}
public void doSomething() {
System.out.println("outter method");
}
public class Inner{
void print() {
doSomething(); // 呼叫外部方法
System.out.println("outter name = " + name); // 使用外部變數
staticMethod(); // 呼叫外部靜態方法
System.out.println("outter staticval = " + staticval); //外部靜態變數
}
}
public static void main(String[] args) {
// 建立內部類別
Outter outter = new Outter();
Inner inner = outter.new Inner();
inner.print();
}
}
outter method
outter name = Outter
outterstatic method
outter staticval = Static val
內部類別是外部類別的成員
外部類別可以宣告一個內部類別的成員變數
1
2
3
4
5
6
public class Outter {
private Inner inner; // 成員屬性是內部類別
public class Inner{
void print() {}
}
}
外部類別可以用new建立內部類別
將成員變數指向內部類別「物件」。
1
2
3
4
5
6
7
8
9
10
public class Outter {
private Inner inner; // 成員屬性是內部類別
public class Inner{
void print() {}
}
public Outter() {
// 建立Outter物件的時候,建立內部類別
inner = new Inner();
}
}
外部類別可以使用內部類的方法
1
2
3
4
5
6
7
8
9
10
11
public class Outter {
private Inner inner; // 成員屬性是內部類別
public class Inner{
void print() {}
}
public Outter() {
// 建立Outter物件的時候,建立內部類別
inner = new Inner();
inner.print(); // 外部類別使用內部類別的方法
}
}
內部類別可以有public、private、protected、default
私有內部類別
內部類別權限設為private,代表只有Outter這個外部類別可以存取,其它類別不能讀取到PrivateInner這個類別。
私有內部類別
1
2
3
4
5
6
7
public class Outter {
private class privateInner {
void print() {
System.out.println("privateInner");
}
}
}
在其它類別呼叫
1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
// 以下程式碼是無法執行的
Outter.privateInner privateInner = outter.new privateInner();
privateInner.print();
}
}
靜態內部類別
進行以下的內容,請先讀過以下2篇文章:
使用靜態內部類別
什麼是靜態內部類別?其實也是一個類別,只是外部類別變成名稱空間,呼叫靜態內部類別的靜態方法,這樣呼叫:
1
外部類別.靜態內部類別.靜態方法();
呼叫靜態方法時,類別名也變成名稱空間,這樣呼叫:
1
類別.靜態方法();
以上呼叫的方法如出一徹。
static關鍵字
在內部類前面加上static的關鍵字就變成靜態內部類別。
1
2
3
4
5
public class Outter {
public static class InnerStaticClass {
}
}
建立new靜態內部類別
語法
外部類別.內部類別 變數 = new 外部類別.內部類別()
注意!靜態內部類別建立的方式為「內部類別」差距很大,不相同。
1
2
3
4
5
6
7
8
9
public class Test {
public static class Static_class {
}
public static void main(String[] args) {
Test.StaticClass staticClass = new Test.StaticClass();
staticClass.inner_memthod();
}
}
靜態內部類別建構子
之前提過靜態內部類別就是類別,只是外部類別變成名稱空間,所以一定有建構子。
1
2
3
4
5
6
7
8
9
10
public class Test {
public static class Static_class {
Static_class() {
System.out.println("靜態內部類別建構子");
}
}
public static void main(String[] args) {
Test.Static_class staticClass = new Test.Static_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
32
33
34
35
36
37
38
public class Test {
public static String static_name = "外部靜態變數";
public String name = "外部成員變數";
private static void staticMethod1() {
System.out.println("外部靜態方法");
}
private void method1() {
System.out.println("外部方法");
}
public static class Static_class {
String innclass_name = "內部變數";
static String innclass_static_name = "內部靜態變數";
public void innerMethod1() {
System.out.println("內部方法");
}
public static void innerStaticMethod1() {
System.out.println("內部靜態方法");
}
// 內部類的靜態方法
public static void inner_static_memthod() {
System.out.println("靜態內部類 靜態方法區塊");
System.out.println("外部類別 靜態變數:" + static_name);
staticMethod1();
System.out.println("靜態內部類 靜態成員屬性innclass_static_name = " + innclass_static_name);
innerStaticMethod1();
}
}
public static void main(String[] args) {
Test.Static_class.inner_static_memthod();
}
}
靜態內部類 靜態方法區塊
外部類別 靜態變數:外部靜態變數
外部靜態方法
靜態內部類 靜態成員屬性innclass_static_name = 內部靜態變數
內部靜態方法
靜態內部類別的成員方法
以下無法存取:
- 外部類別成員屬性
- 外部類別成員方法
以下都可以存取
- 內部類別成員屬性
- 內部類別成員方法
- 外部類別靜態屬性
- 外部類別靜態方法
- 內部類別靜態屬性
- 內部類別靜態方法
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
32
33
34
35
36
37
38
39
40
41
42
public class Test {
public static String static_name = "外部靜態變數";
public String name = "外部成員變數";
private static void staticMethod1() {
System.out.println("外部靜態方法");
}
private void method1() {
System.out.println("外部方法");
}
public static class Static_class {
String innclass_name = "內部變數";
static String innclass_static_name = "內部靜態變數";
public void innerMethod1() {
System.out.println("內部方法");
}
public static void innerStaticMethod1() {
System.out.println("內部靜態方法");
}
public void inner_memthod() {
System.out.println("靜態內部類 成員方法(非靜態)區塊");
System.out.println("外部類別 靜態變數:" + static_name);
staticMethod1();
System.out.println("靜態內部類 成員屬性innclass_name = " + innclass_name);
System.out.println("靜態內部類 靜態成員屬性innclass_static_name = " + innclass_static_name);
innerMethod1();
innerStaticMethod1();
// method1();
// System.out.println("外部類別 變數:" + name);
}
}
public static void main(String[] args) {
Test.Static_class staticClass = new Test.Static_class();
staticClass.inner_memthod();
}
}
靜態內部類 成員方法(非靜態)區塊
外部類別 靜態變數:外部靜態變數
外部靜態方法
靜態內部類 成員屬性innclass_name = 內部變數
靜態內部類 靜態成員屬性innclass_static_name = 內部靜態變數
內部方法
內部靜態方法
使用到靜態內部類別才會被建立
注意!當靜態內部類別要用到的時候,才會初始化。
初始化程式碼
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
32
33
34
public class Test {
{
System.out.println("外部匿名區塊");
}
static {
System.out.println("外部靜態區塊");
}
Test() {
System.out.println("外部建構子區塊");
}
public static void staticMethod1() {
System.out.println("外部靜態方法");
}
public static class Static_class {
Static_class() {
System.out.println("內部類別建構子");
}
{
System.out.println("內部匿名區塊");
}
static {
System.out.println("內部靜態區塊");
}
public static void innerStaticMethod1() {
System.out.println("內部靜態方法");
}
}
}
未使用靜態內部類別
1
2
3
public static void main(String[] args) {
Test.staticMethod1();
}
外部靜態區塊
外部靜態方法
由以上的結果可以發現,呼叫外部類別的靜態方法時,不會呼叫任何靜態內部類別區塊。
使用靜態內部類別
1
2
3
public static void main(String[] args) {
Test.Static_class.innerStaticMethod1();
}
外部靜態區塊
內部靜態區塊
內部靜態方法
由以上的結果可以發現,呼叫靜態內部類別的方法時,會呼叫靜態內部類別的「靜態區塊」。
建立外部類別
1
2
3
public static void main(String[] args) {
Test test = new Test();
}
外部靜態區塊
外部匿名區塊
外部建構子區塊
由以上的結果可以發現,外部類別建立的時候,完全不會建立靜態內部類別的任何代碼。
建立靜態內部類別
1
2
3
public static void main(String[] args) {
Test.Static_class test = new Test.Static_class();
}
外部靜態區塊
內部靜態區塊
內部匿名區塊
內部類別建構子
由以上的結果可以發現,外部類別只是名稱空間,建立靜態內部類別的時候,外部類別只會呼叫「靜態區塊」,外部的「匿名區塊」與外部「建構子」,完全沒被呼叫。
而靜態內部類別的「靜態區塊」與「匿名區塊」與「建構子」全呼叫。
靜態內部類別與jvm
static方法、static變數、static靜態內部類別,是在JVM啟動時,ClassLoader類別載入器就已經先丟進Method area(Metaspace)的靜態資料區中。
區域內部類別
- 定義在方法或代碼塊中的類別
- 不能使用 public、private 或 protected 修飾
- 只能被該方法或代碼塊內的代碼存取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test2 {
public void method1() {
class LocalInner {
public void localMethod1() {
System.out.println("區域內部類別中的方法");
}
}
LocalInner localInner = new LocalInner();
localInner.localMethod1();
}
public static void main(String[] args) {
Test2 test = new Test2();
test.method1();
}
}
區域內部類別中的方法