转自:http://www.cnblogs.com/aigongsi/archive/2012/04/24/2467183.html
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 ,
member nested class(成员嵌套类) :成员嵌套类 作为
local nested class (局部嵌套类): 局部嵌套类定义在
anonymous nested class(匿名嵌套类):匿名嵌套类没有显示的定义一个类,直接通过new 的方法创建类的实例。一般回调模式情况下使用的比较多
member nested class
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() {
}
};
}
}
|
在大多数情况下,一般把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
嵌套类访问规则
Static Nested Classes 以及 inner classes 有一些限制规则,下面介绍一下这些规则。
- Static Nested Classes访问规则
用Static修饰的Nested Classes,只能访问外部类的非static变量。对于public 的 static
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
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
局部类
局部类可以定义在一个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);
}
}
}
}
|
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编译器对嵌套类的处理才可以深入了解嵌套类细节。