简单的说,内部(inner)类指那些类定义代码被置于其它类定义中的类;而对于一般的、类定义代码不嵌套在其它类定义中的类,称为顶层(top-level)类。对于一个内部类,包含其定义代码的类称为它的外部(outer)类。
1Static member class(静态成员类)
类声明中包含“static”关键字的内部类。如以下示例代码,
Inner1/Inner2/Inner3/Inner4就是Outer的四个静态成员类。静态成员类的使用方式与一般顶层类的使用方式基本相同。
publicclassOuter{//just like static method, static member class has public/private/default access privilege levels//access privilege level: publicpublicstaticclassInner1 {publicInner1() {//Static member inner class can access static method of outer classstaticMethod();//Compile error: static member inner class can not access instance method of outer class//instanceMethod();}
}//access privilege level: defaultstaticclassInner2 {
}//access privilege level: privateprivatestaticclassInner3 {//define a nested inner class in another inner classpublicstaticclassInner4 {
}
}privatestaticvoidstaticMethod() {//cannot define an inner class in a method/*public static class Inner4() {
}*/}privatevoidinstanceMethod() {//private static member class can be accessed only in its outer class definition scopeInner3 inner3=newInner3();//how to use nested inner classInner3.Inner4 inner4=newInner3.Inner4();
}
}classTest {
Outer.Inner1 inner1=newOuter.Inner1();//Test and Outer are in the same package, so Inner2 can be accessed hereOuter.Inner2 inner2=newOuter.Inner2();//Compile error: Inner3 cannot be accessed here//Outer.Inner3 inner3 = new Outer.Inner3();}
1.1静态成员类特性
静态成员类可访问外部类的任一静态字段或静态方法
像静态方法或静态字段一样,静态成员类有public/private/default权限修饰符
1.2静态成员类约束
静态成员类不能与外部类重名
像外部类的静态方法一样,不能直接访问外部类的实例字段和实例方法
静态成员类只能定义于外部类的顶层代码或外部类其它静态成员类的顶层代码中(嵌套定义);不能定义于外部类的某个函数中。
1.3新增语法
如示例代码所示,可以以“OuterClass.InnerClass”的方式来引用某个内部类。
1.4什么时候使用静态成员类
B为A的辅助类,且只为A所用时,可将B定义为A的静态成员类。例如JDK中的LinkedList类就有Entry静态成员类:
publicclassLinkedListextendsAbstractSequentialList…;privatestaticclassEntry{
E element;
Entrynext;
Entryprevious;
Entry(E element, Entrynext, Entryprevious) {this.element=element;this.next=next;this.previous=previous;
}
}
…;
}
显然,Entry用来表示LinkedList中的一个结点,只被LinkedList自身使用。
2Member class(成员类)
一个静态成员类,若去掉“static”关键字,就成为成员类。如下示例代码,Inner1/Inner2/Inner3/Inner4就是Outer的四个成员类
publicclassOuter {//just like instance method, member class has public/private/default access privilege levelsprivateintdata;//access privilege level: publicpublicclassInner1 {privateintdata;privateintdata1;publicInner1() {//member class can access its outer class' instance field directlydata1=1;//itself data fielddata=1;//its outer class instance fieldOuter.this.data=1;
}
}//access privilege level: defaultclassInner2 {//can not define static filed, method, class in member class//static int j = 1;//but, "static final" compound is allowedstaticfinalintCONSTANT=1;
}//access privilege level: privateprivateclassInner3 {publicclassInner4 {
}
}//in fact, Inner5 is not a member class but a static member classinterfaceInner5 {
}privatestaticvoidstaticMethod() {//can not create a member class instance directly in outer class' static method//Inner1 inner1 = new Inner1();}privatevoidinstanceMethod() {//can create a member class instance in outer class' instance methodInner1 inner1=newInner1();
}
}classTest {publicTest() {//cannot create member class instance directly in class other than outer class//Outer.Inner2 inner2 = new Outer.Inner2();//create a member class instance outside it's outer classOuter outer=newOuter();
Outer.Inner1 inner1=outer.newInner1();
}
}
2.1成员类特性
·类似于外部类的实例函数,成员类有public/private/default权限修饰符
·一个成员类实例必然所属一个外部类实例,成员类可访问外部类的任一个实例字段和实例函数。
2.2成员类约束
成员类不能与外部类重名
不能在成员类中定义static字段、方法和类(static final形式的常量定义除外)。因为一个成员类实例必然与一个外部类实例关联,这个static定义完全可以移到其外部类中去
成员类不能是接口(interface)。因为成员类必须能被某个外部类实例实例化,而接口是不能实例化的。事实上,如示例代码所示,如果你以成员类的形式定义一个接口,该接口实际上是一个静态成员类,static关键字对inner interface是内含(implicit)的。
2.3新增语法
一个成员类实例必然所属于其外部类的一个实例,那么如何在成员类内部获得其所属外部类实例呢?如示例代码所示,采用“OuterClass.this”的形式。
2.4指定内部类实例所属的外部类实例
内部类实例可在其外部类的实例方法中创建,此新创建内部类实例所属的外
部类实例自然就是创建它的外部类实例方法对应的外部类实例。
另外,如示例代码所示,对于给定的一个外部类实例outerClass,可以直接创建其内部类实例,语法形式为:
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
2.5什么时候使用成员类
成员类的显著特性就是成员类能访问它的外部类实例的任意字段与方法。方便一个类对外提供一个公共接口的实现是成员类的典型应用。
以JDK Collection类库为例,每种Collection类必须提供一个与其对应的Iterator实现以便客户端能以统一的方式遍历任一Collection实例。每种Collection类的Iterator实现就被定义为该Collection类的成员类。例如JDK中AbstractList类的代码片断:
publicabstractclassAbstractListextendsAbstractCollectionimplementsList{privateclassItrimplementsIterator{
………;
}publicIteratoriterator() {returnnewItr();
}
}
因为定义在AbstractList中的Itr可访问AbstractList中的任意字段和方法,所以很方便实现Iterator,无需AbstractList对外暴露更多的接口。
试想,如果没有成员类机制,只有在AbastractList源码之外定义一个实现Iterator的类Itr,该类有一个AbstractList实例成员list,为了Itr能获取list的内部信息以便实现遍历,AbstractList必然要向Itr开放额外的访问接口。
3Local class(局部类)
对一个静态成员类,去掉其声明中的“static”关键字,将其定义移入其外部类
的静态方法或静态初始化代码段中就成为了局部静态成员类。
对一个成员类,将其定义移入其外部类的实例方法或实例初始化代码中就成为了局部成员类。
局部静态成员类与静态成员类的基本特性相同。例如,都只能访问外部类的静态字段或方法,但不能访问外部类的实例字段和实例方法等。
局部成员类与成员类的基本特性相同。例如,局部成员类实例必属于其外部类的一个实例,可通过OuterClass.this引用其外部类实例等。
另外,局部类也有其自己的特性,如以下代码所示:
3.1局部类特性
如示例代码所示,局部类能且只能访问其所属代码段中的声明为final的局部
变量。为什么只能访问声明为final的局部变量呢?我们知道,局部变量在其所属的代码段(譬如某个函数)执行完毕后就会被回收,而一个局部类的实例却可以在其类定义所属代码段执行完毕后依然存在,如果它可操控非final的局部变量,用户就可以通过该实例修改已不存在的局部变量,无意义。
3.2局部类约束
如示例代码所示,内部类只在定义它的代码段中可见,不能在它所属代码段之外的代码中使用;因此也就没有public/private/default权限修饰符(无意义)
不能以局部类形式定义一个接口。局部类只在其所属代码段中可见,定义这样的接口无意义
局部类类名不能与其外部类类名重复
3.3什么时候使用局部类
局部类大部分以匿名类的形式使用。
4Anonymous class(匿名类)
没有类名的局部类就是匿名类。用一条语句完成匿名类的定义与实例创建。例
如如下代码:
publicclassOuter {publicvoidinstanceMethod() {//define a nonymous class which implements Action interface and creat an instance of itAction action=newAction() {publicvoiddoAction() {
System.out.println("a simple anonymous class demo");
}};
action.doAction();//define a nonoymous class which extends BaseClass and create an instance of itnewBaseClass(5) {publicvoidprintData(){
System.out.println("data ="+getData());
}
}.printData();//"data = 5" will be outputed}
}interfaceAction {voiddoAction();
}classBaseClass {privateintdata;publicBaseClass (intdata) {this.data=data;
}publicintgetData() {returndata;
}
}
4.1匿名类特性与约束
匿名类是一种特殊的局部类。局部类的特性与约束都适用与它。
4.2新增语法
4.2.1继承自某个基类的匿名类
new ( [ ] ) { }
创建匿名类实例时,“argument-list”将被传入其基类(即class-name)对应的构造函数。
4.2.2实现某个接口的匿名类
new () { }
4.3什么时候使用匿名类
该类定义代码段很短
只需要创建该类的一个实例
类的定义代码与类的使用代码紧邻
使用匿名不影响代码的易读性
譬如,如下实现类似与c的callback功能的代码就是匿名类的典型应用:
File f=newFile("/src");//The directory to list//Now call the list() method with a single FilenameFilter argument//Define and instantiate an anonymous implementation of FilenameFilter//as part of the method invocation expression.String[] filelist=f.list(newFilenameFilter() {publicbooleanaccept(File f, String s) {returns.endsWith(".java"); }
});//Don't forget the parenthesis and semicolon that end the method call!
publicclassOuter {privateintinstanceField;privatestaticintstaticField;//define a local member class in instance code block{intlocalVirable1=0;finalintlocalVirable2=1;classInner1 {publicInner1() {//can access its outer class' field and method directlyinstanceField=1;//use OuterClass.this to get its corresponding outer class instanceOuter.this.instanceField=1;//can not access the not final local virable in its containing code block//System.out.print(localVirable1);//can access the final local virable in its containing code blockSystem.out.print(localVirable2);
}
}//local class can not have privilege modifier/*public class inner2 {
}*/}//define a local static member class in static code blockstatic{classInner2 {publicInner2() {
staticField=1;//can not access instance field and method in a local static member class//intanceField = 2;}
}
}publicvoidintanceMethod() {//define a local class in its out class' instance methodclassInner3 {
}//local class is visible only in its containning code block//Outer.Inner2 inner2;}privatestaticvoidstaticMethod() {//define a local static member class in its out class' static methodclassInner4 {publicInner4() {
staticField=2;
}
}//can not define a interface as a local class/*interface I {
}*/}
}