java嵌套类(Nested Classes)总结
Posted yangl517
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java嵌套类(Nested Classes)总结相关的知识,希望对你有一定的参考价值。
转自: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编译器对嵌套类的处理才可以深入了解嵌套类细节。
以上是关于java嵌套类(Nested Classes)总结的主要内容,如果未能解决你的问题,请参考以下文章
Java Nested Classes(内部类~第一篇英文技术文档翻译)
Java面试题11 什么是内部类?Static Nested Class 和 Inner Class的不同。