Java內部類或嵌套類是在類或接口中聲明的類。我們使用內部類在一個地方邏輯地分組類和接口,以便它更可讀和可維護。此外,它還可以訪問外部類的成員,包括私有數據成員和方法。
內部類的優點:
- 嵌套類代表了一種特殊的類型關系:能訪問外部類的所有數據成員和方法(包括私有的)
- 嵌套類用於開發更可讀和可維護的代碼,因為它只在一個地方對類和接口進行邏輯分組。
- 代碼優化:它需要更少的代碼
問題:
- 編輯器為member inner class(成員內部類)生成的內部代碼是什么?
- 創建annonymous inner class(匿名內部類)的兩種方式是什么?
- 我們可以在local inner class(局部內部類)中訪問非final局部變量嗎?
- 如何訪問static nested class(靜態嵌套類)?
- 接口中可以定義類嗎?
- 類中可以定義接口嗎?
nested class(嵌套類)和inner class(內部類)的區別於聯系
內部類是嵌套類的一部分,非靜態嵌套類被視為內部類
嵌套類的類型
有靜態嵌套類和非靜態嵌套類兩種類型。非靜態嵌套類被視為內部類
- Non-static nested class (inner class) 非靜態嵌套類:
- member inner class(成員內部類)
- annonymous inner class(匿名內部類)
- local inner class(局部內部類)
- static nested class靜態嵌套類
1.成員內部類
在類內部創建但在方法之外的非靜態類稱為成員內部類。語法:
1 class TestMemberOuter1{ 2 private int data=30; 3 class Inner{ 4 void msg(){System.out.println("data is "+data);} 5 } 6 public static void main(String args[]){ 7 TestMemberOuter1 obj=new TestMemberOuter1(); 8 TestMemberOuter1.Inner in=obj.new Inner(); 9 in.msg(); 10 } 11 }
成員內部類的工作原理:
Java編譯器在內部類的情況下創建兩個類文件。內部類的類文件名是“outer$inner”。如果要實例化內部類,則必須創建外部類的實例。在這種情況下,內部類的實例是在外部類的實例中創建的。
編譯器生成的內部代碼:
java編譯器創建一個名為"outer$inner"的類文件。成員內部類具有外部類的引用,這就是為什么成員內部類可以訪問外部類的所有數據成員的原因
import java.io.PrintStream; class Outer$Inner { final Outer this$0; Outer$Inner() { super(); this$0 = Outer.this; } void msg() { System.out.println((new StringBuilder()).append("data is ") .append(Outer.access$000(Outer.this)).toString()); } }
2.匿名內部類
一個沒有名字的類在Java中被稱為匿名內部類。如果您必須重寫類或接口的方法,則應該使用它。可以通過兩種方式創建Java匿名內部類
- 類(可以是抽象類或具體類)
- 接口
java匿名內部類舉例
1 abstract class Person{ 2 abstract void eat(); 3 } 4 class TestAnonymousInner{ 5 public static void main(String args[]){ 6 Person p=new Person(){ 7 void eat(){System.out.println("nice fruits");} 8 }; 9 p.eat(); 10 } 11 }
匿名內部類的工作原理
- 類被創建,但是它的名稱由編譯器決定,編譯器實現Person類,並實現eat方法
- 創建匿名類的對象,該對象由Person類型的p引用變量引用。
編譯器生成的代碼
import java.io.PrintStream; static class TestAnonymousInner$1 extends Person { TestAnonymousInner$1(){} void eat() { System.out.println("nice fruits"); } }
3. 局部內部類
在方法中創建的類稱為Java中的本地內部類。如果要調用本地內部類的方法,必須在該方法中實例化該類。
局部內部類舉例
1 public class localInner1{ 2 private int data=30;//instance variable 3 void display(){ 4 class Local{ 5 void msg(){System.out.println(data);} 6 } 7 Local l=new Local(); 8 l.msg(); 9 } 10 public static void main(String args[]){ 11 localInner1 obj=new localInner1(); 12 obj.display(); 13 } 14 }
編譯器生成的內部類:
1 import java.io.PrintStream; 2 class localInner1$Local 3 { 4 final localInner1 this$0; 5 localInner1$Local() 6 { 7 super(); 8 this$0 = Simple.this; 9 } 10 void msg() 11 { 12 System.out.println(localInner1.access$000(localInner1.this)); 13 } 14 }
規則:
- 局部內部類不能聲明為public、protected、private,只能是默認訪問權限
- 局部內部類不能被外部方法調用
- 局部內部類不能訪問非final局部變量在JDK1.7之前,但是可以訪問final變量;在JDK1.8以后,局部內部類也可以訪問非final局部變量
4.靜態嵌套類
在類中創建的靜態類在Java中稱為靜態嵌套類。它不能訪問非靜態數據成員和方法。它可以由外部類名訪問。
- 它可以訪問包括私有的外部類的靜態數據成員。
- 靜態嵌套類不能訪問非靜態(實例)數據成員或方法
靜態嵌套類舉例
class TestOuter1{ static int data=30; static class Inner{ void msg(){System.out.println("data is "+data);} } public static void main(String args[]){ TestOuter1.Inner obj=new TestOuter1.Inner(); obj.msg(); } }
在這個例子中,你需要創建靜態嵌套類的實例,因為他含有實例方法msg()。但是你不需要創建外部類的實例,因為嵌套類是靜態的並且靜態的屬性、方法、類在沒有對象情況下可以被訪問
編譯器生成的代碼:
1 import java.io.PrintStream; 2 static class TestOuter1$Inner 3 { 4 TestOuter1$Inner(){} 5 void msg(){ 6 System.out.println((new StringBuilder()).append("data is ") 7 .append(TestOuter1.data).toString()); 8 } 9 }
5. 嵌套接口
在另一個接口或類中聲明的接口稱為嵌套接口。嵌套接口用於對相關接口進行分組,以便它們易於維護。嵌套接口必須由外部接口或類引用。它不能直接訪問。
嵌套接口要記住的要點
- 嵌套接口在接口內聲明時必須是公共的,但是如果在類內聲明,則它可以具有任何訪問修飾符。
- 嵌套接口隱式地聲明為靜態的
嵌套接口在接口內聲明舉例
interface Showable{ void show(); interface Message{ void msg(); } } class TestNestedInterface1 implements Showable.Message{ public void msg(){System.out.println("Hello nested interface");} public static void main(String args[]){ Showable.Message message=new TestNestedInterface1();//upcasting here message.msg(); } }
java編輯器為嵌套接口生成的代碼
public static interface Showable$Message { public abstract void msg(); }
我們能在接口中定義一個類嗎?
是的,我們可以在接口中定義一個類,java編譯器將會創建一個靜態嵌套類
