Java嵌套類(Nested Classes)總結
Nested Classes定義
在java語言規範裏麵,嵌套類(Nested Classes)定義是:
A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class.
說的簡單一點,就是定義在類裏麵的類。一般把定義內部類的外圍類成為包裝類(enclosing class)或者外部類
嵌套類分類
根據nested class定義的地方,可以分為member nested class,local nested class , anonymous nested class
member nested class(成員嵌套類) :成員嵌套類 作為 enclosing class 的成員定義的,成員嵌套類有enclosing class屬性
local nested class (局部嵌套類): 局部嵌套類定義在 enclosing class 的方法裏麵,局部嵌套類有enclosing class 屬性和enclosing method 屬性
anonymous nested class(匿名嵌套類):匿名嵌套類沒有顯示的定義一個類,直接通過new 的方法創建類的實例。一般回調模式情況下使用的比較多
member nested class 可以使用public,private,protected訪問控製符,也可以用static,final關鍵字
local nested class 可以使用final關鍵字
anonymous nested class 不使用任何關鍵字和訪問控製符
見下麵的代碼
public class EnclosingClass
{
public static final class NestedMemberClass
{
}
public void nestedLocalClass()
{
final class NestedLocalClass
{
}
}
public void nestedAnonymousClass()
{
new Runnable()
{
@Override
public void run()
{
}
};
}
} |
如果你想學習java可以來這個群,首先是二二零,中間是一四二,最後是九零六,裏麵有大量的學習資料可以下載
在大多數情況下,一般把nested classes 分為兩種:
Static Nested Classes(靜態嵌套類): 就是用static修飾的成員嵌套類
InnerClass:靜態嵌套類之外所有的嵌套類的總稱,也就是沒有用static定義的nested classes,Inner Classes 不能定義為static,不能有static方法和static初始化語句塊。在JLS(java語言規範)裏麵是這麼定義的:
An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes may not declare static initializers (§8.7) or member inter- faces
其中Inner Class又可以分為三種:
1 inner member classes :沒有用static 修飾的成員內部類
2 local inner classes : 定義在方法裏麵的內部類,方法可以是static的也可以是非static的,也可以是構造器方法。
3 anonymous inner classes :定義在方法裏麵匿名類,方法可以是static的也可以是非static的
嵌套類訪問規則
Static Nested Classes 以及 inner classes 有一些限製規則,下麵介紹一下這些規則。
- Static Nested Classes訪問規則
用Static修飾的Nested Classes,隻能訪問外部類的非static變量。對於public 的 static Nested Classes 可以用 new 外部類.內部類()的方式直接創建。而默認的static Nested Classes 可以在同一包名下,用 new 外部類.內部類()的方式創建。其實和外部類的方式差不多。靜態成員類可以使用訪問控製符,可以使用static修飾,可以是abstract抽象類
public class StaticNestedClass
{
//
私有局部
private int i
= 0 ;
//
靜態
public static int j
= 0 ;
//
不變值
private final int k
= 0 ;
//
static final
private static final int m
= 0 ;
//
靜態嵌套內,這裏不是innerclass,可以直接new出來
public static class PublicNestedClass
{
private void test1()
{
//
System.out.println(i); 非innerClass不能訪問enclosing類的非static屬性
System.out.println(j);
System.out.println(m);
//
System.out.println(k); 非innerClass不能訪問enclosing類的非static屬性
}
//
可以定義static方法
private static void test2()
{
}
}
//
靜態嵌套內,這裏不是innerclass,由於是私有的,不可以直接new出來
private static class PrivateNestedClass
{
}
} |
下麵的例子演示了static Nested class的創建
public class TestClass
{
public static void main(String[]
args) {
//任何地方都可以創建
StaticNestedClass.PublicNestedClass
publicNestedClass = new StaticNestedClass.PublicNestedClass();
//可以在同一package下創建
StaticNestedClass.DefaultNestedClass
defaultNestedClass = new StaticNestedClass.DefaultNestedClass();
//編譯錯誤,無法訪問內部內
//StaticNestedClass.PrivateNestedClass
privateNestedClass = new StaticNestedClass.PrivateNestedClass();
}
} |
- Inner Class訪問規則
inner member classes(內部成員類) 可以訪問外部類的所有實例屬性,靜態屬性。因為內部成員類持有一個外部對象的引用,內部類的實例可以對外部類的實例屬性進行修改。如果是public的 inner member classes,可以通過 外部類實例.new 內部類()的方式進行創建,當調用內部類的構造器的時候,會把當前創建的內部類對象實例中持有的外部對象引用賦值為當前創建內部類的外部類實例。內部成員類可以是使用訪問控製符,可以定義為final,也可以是抽象類。
public class MemberInnerClass
{
//
私有局部
public int i
= 0 ;
//
靜態
private static int j
= 0 ;
//
不變值
private final int k
= 0 ;
//
static final
private static final int m
= 0 ;
public class PublicMemberInnerClass
{
//
enclosing Class的屬性都可以訪問
public void test()
{
System.out.println(i);
System.out.println(j);
System.out.println(m);
System.out.println(k);
}
public MemberInnerClass
getOutterClass() {
return MemberInnerClass. this ;
}
//
這裏會報錯,不允許定義static方法
//
private static final void test();
}
//
私有的innerclass 外部不能訪問
private class PrivateMemberInnerClass
{
}
//
公開局部類,外部可以訪問和創建,但是隻能通過OutterClass實例創建
class DefaultMemberInnerClass
{
public MemberInnerClass
getOutterClass() {
return MemberInnerClass. this ;
}
}
} |
下麵例子演示了內部成員類的創建
public class TestClass
{
public static void main(String[]
args) {
//
任何地方都可以創建
MemberInnerClass
t = new MemberInnerClass();
//
可以創建,pmic裏麵保存對t的引用
MemberInnerClass.PublicMemberInnerClass
pmic = t. new PublicMemberInnerClass();
//
可以在同一package下創建,dmic保存對t的引用
MemberInnerClass.DefaultMemberInnerClass
dmic = t. new DefaultMemberInnerClass();
//
編譯錯誤,無法訪問內部內
//
MemberInnerClass.PrivateMemberInnerClass pmic = t.new
//
PrivateMemberInnerClass();
//
下麵驗證一下outterClass是同一個對象
System.out.println(pmic.getOutterClass()
== t);
System.out.println(dmic.getOutterClass()
== t);
}
} |
運行程序,打印結果:
true true |
2 local inner classes(局部類)
局部類 定義在類方法裏麵。這個方法既可以是靜態方法,也可以是實例方法,也可以是構造器方法或者靜態初始化語句塊。
局部類可以定義在一個static上下文裏麵 和 非static上下文裏麵。局部類不能有訪問控製符(private,public,protected修飾),可以是抽象的,也可以定義為final
定義在static上下文(static 字段初始化,static初始化塊,static方法)裏麵的local inner classes 可以訪問類的靜態屬性,如果定義在靜態方法裏麵的局部類,還可以方法裏麵定義的final變量。在static上下文定義的局部類,沒有指向父類實例變量的引用,因為static方法不屬於類的實例,屬於類本身。而且局部類不能在外部進行創建,隻能在方法調用的時候進行創建
public class LocalInnerClass
{
//
私有局部
private int i
= 0 ;
//
靜態
public static int j
= 0 ;
//
不變值
private final int k
= 0 ;
//
static final
private static final int m
= 0 ;
public static void test()
{
final int a
= 0 ;
int b
= 0 ;
//
local inner class不能夠有訪問控製符 比如public private
abstract class LocalStaticInnerClass
{
//
local inner class不能定義靜態屬性
//
private static int c;
private int d
= 0 ;
public LocalStaticInnerClass()
{
//
可以訪問方法裏麵定義的final 變量
System.out.println(a);
//
不能訪問b 因為b不是final
//
System.out.println(b);
//
定義在static上下文裏麵的local inner class 不能訪問外部類的非static字段
//
System.out.println(i);
//
System.out.println(k);
System.out.println(j);
System.out.println(m);
}
//
local inner class不能定義靜態方法
//
public static void test(){}
}
}
public void test2()
{
final int a
= 0 ;
int b
= 0 ;
final class LocalNonStaticInnerClass{
public LocalNonStaticInnerClass()
{
//定義在非static上下文的local
inner class 可以訪問外部類的所有屬性
System.out.println(i);
System.out.println(k);
System.out.println(j);
System.out.println(m);
}
}
}
} |
3 anonymous inner classes (匿名類)也是定義在方法裏麵,匿名類和局部類訪問規則一樣,隻不過內部類顯式的定義了一個類,然後通過new的方式創建這個局部類實例,而匿名類直接new一個類實例,沒有定義這個類。匿名類最常見的方式就是回調模式的使用,通過默認實現一個接口創建一個匿名類然後,然後new這個匿名類的實例。
public class AnonymousInnerClass
{
//訪問規則和局部類一樣
public void test()
{
//匿名類實現
new Thread( new Runnable()
{
@Override
public void run()
{
}
}).start();
//非匿名類實現
class NoneAnonymousClass implements Runnable{
public void run()
{
}
}
NoneAnonymousClass
t = new NoneAnonymousClass();
new Thread(t).start();
}
} |
嵌套類的層次
嵌套類是可以有層次的,也就是說嵌套類裏麵還是定義類,成為嵌套類中的嵌套類。虛擬機如何保證嵌套類正確的嵌套層層次?
對於merber class,內部嵌套類的可以表示為 A$B 其中A為外部類,B為內部成員類 ,如果B裏麵又有成員為C的嵌套類,那麼C就可以表示為A$B$C,如果A定義了兩個同名member class,那麼編譯器就會報錯。如果B裏麵又包含了為名B的nested class,則編譯器會報錯.
對於local inner Class,局部類可以表示為A$1B的方式,其中A為外部類,B為第一個局部類 如果在不同的方法裏麵定義了同名的局部類B,編譯器是可以編譯通過的,那麼定義的第二個局部類B可以表示為A$2B,如果在同一個方法裏麵同定義兩個相同的局部類B,那麼編譯錯是要報錯的。如果B裏麵又定義了同名的成員類,則可以表示為A$1B$B。
對於anonymous inner classes,匿名類可以表示為A$1的方式,代表程序裏麵有一個匿名類。如果有N個,可以表示為A$N的方式(N為自然數).
看看下麵的例子
public class NestedClassLevel
{
class A
{
//
編譯器會報錯,A裏麵不能在定義名為A的nested classes
//
class A{}
public void test()
{
class B
{
}
}
}
//可以在繼續定義B
class B
{
public void test(){
//可以無限定義匿名類
new Runnable()
{
public void run()
{
//可以無限定義匿名類
new Runnable()
{
public void run()
{
}
};
}
};
}
}
//
隻能定義一個B
//
class B{}
public void test()
{
//
可以定義A
class A
{
public void test()
{
//可以有同名的局部類B和成員類B
class B
{
public void test()
{
}
}
//局部類A裏麵不能在定義A
//class
A{}
}
}
//可以有同名的局部類B和成員類B
class B
{
}
}
} |
對於定義在非static上下文裏麵的nested類層次,比如A$B$1C ,則最內層的嵌套類C有一個指向B實例的引用,B有一個指向A實例的引用,最終最內層的嵌套類可以訪問A中的屬性可以方法,一般把B成為A的直接嵌套類。但是A不可以訪問B或者C中屬性或者方法。
nested interface
由於interface默認是定義為一個 public static的特殊類,所以interface可以直接作為 static member class。可以通過A.B的方式進行訪問。
nested class的應用
在java提供的基本類庫裏麵,大量使用nested classes。比如我們知道的map類。其中 Map類裏麵有一個定義了Entry類abstract inner class。所以我們在遍曆map的時候,一般使用
for (Map.Entry entry:map.entrySet()){
}
總結:nested類是java裏麵比較複雜的一個概念,必須詳細了解jvm中對於嵌套類的實現以及java編譯器對嵌套類的處理才可以深入了解嵌套類細節。
最後更新:2017-04-27 11:31:02