Java 内部类( Inner Class )
简单的说,内部( inner)类指那些类定义代码被置于其它类定义中的类;而对于一般的、类定义代码不嵌套在其它类定义中的类,称为顶层( top-level)类。对于一个内部类,包含其定义代码的类称为它的外部( outer)类。
1 Static member class (静态成员类)
类声明中包含“ static” 关键字的内部类。如以下示例代码,
Inner1/Inner2/Inner3/Inner4 就是 Outer 的四个静态成员类。静态成员类的使用方式与一般顶层类的使用方式基本相同。
public
class
Outer{
//just like static method, static member class has public/private/default access privilege levels
//access privilege level: public
public
static
class
Inner1 {
public
Inner1() {
//Static member inner class can access static method of outer class
staticMethod();
//Compile error: static member inner class can not access instance method of outer class
//instanceMethod();
}
}
//access privilege level: default
static
class
Inner2 {
}
//access privilege level: private
private
static
class
Inner3 {
//define a nested inner class in another inner class
public
static
class
Inner4 {
}
}
private
static
void
staticMethod() {
//cannot define an inner class in a method
/*public static class Inner4() {
}*/
}
private
void
instanceMethod() {
//private static member class can be accessed only in its outer class definition scope
Inner3 inner3 =
new
Inner3();
//how to use nested inner class
Inner3.Inner4 inner4 =
new
Inner3.Inner4();
}
}
class
Test {
Outer.Inner1 inner1 =
new
Outer.Inner1();
//Test and Outer are in the same package, so Inner2 can be accessed here
Outer.Inner2 inner2 =
new
Outer.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 静态成员类:
public
class
LinkedList<E>
extends
AbstractSequentialList<E>
…;
private
static
class
Entry<E> {
E element;
Entry<E> next;
Entry<E> previous;
Entry(E element, Entry<E> next, Entry<E> previous) {
this
.element = element;
this
.next = next;
this
.previous = previous;
}
}
…;
}
显然, Entry 用来表示 LinkedList 中的一个结点,只被 LinkedList 自身使用。
2 Member class(成员类)
一个静态成员类,若去掉“
static”关键字,就成为成员类。如下示例代码,
Inner1/Inner2/Inner3/Inner4就是
Outer的四个成员类
public
class
Outer {
//just like instance method, member class has public/private/default access privilege levels
private
int
data;
//access privilege level: public
public
class
Inner1 {
private
int
data;
private
int
data1;
public
Inner1() {
//member class can access its outer class' instance field directly
data1 =
1;
//itself data field
data =
1;
//its outer class instance field
Outer.
this
.data =
1;
}
}
//access privilege level: default
class
Inner2 {
//can not define static filed, method, class in member class
//static int j = 1;
//but, "static final" compound is allowed
static
final
int
CONSTANT =
1;
}
//access privilege level: private
private
class
Inner3 {
public
class
Inner4 {
}
}
//in fact, Inner5 is not a member class but a static member class
interface
Inner5 {
}
private
static
void
staticMethod() {
//can not create a member class instance directly in outer class' static method
//Inner1 inner1 = new Inner1();
}
private
void
instanceMethod() {
//can create a member class instance in outer class' instance method
Inner1 inner1 =
new
Inner1();
}
}
class
Test {
public
Test() {
//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 class
Outer outer =
new
Outer();
Outer.Inner1 inner1 = outer.
new
Inner1();
}
}
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 类的代码片断:
public
abstract
class
AbstractList<E>
extends
AbstractCollection<E>
implements
List<E> {
private
class
Itr
implements
Iterator<E> {
………;
}
public
Iterator<E> iterator() {
return
new
Itr();
}
}
因为定义在 AbstractList 中的 Itr 可访问 AbstractList 中的任意字段和方法,所以很方便实现 Iterator ,无需 AbstractList 对外暴露更多的接口。
试想,如果没有成员类机制,只有在 AbastractList 源码之外定义一个实现 Iterator 的类 Itr ,该类有一个 AbstractList 实例 成员 list ,为了 Itr 能获取 list 的内部信息以便实现遍历, AbstractList 必然要向 Itr 开放额外的访问接口。
3 Local class(局部类)
对一个静态成员类,去掉其声明中的“ static” 关键字,将其定义移入其外部类
的静态方法或静态初始化代码段中就成为了局部静态成员类。
对一个成员类,将其定义移入其外部类的实例方法或实例初始化代码中就成为了局部成员类。
局部静态成员类与静态成员类的基本特性相同。例如,都只能访问外部类的静态字段或方法,但不能访问外部类的实例字段和实例方法等。
局部成员类与成员类的基本特性相同。例如,局部成员类实例必属于其外部类的一个实例,可通过 OuterClass.this 引用其外部类实例等。
另外,局部类也有其自己的特性,如以下代码所示:
public
class
Outer {
private
int
instanceField;
private
static
int
staticField;
//define a local member class in instance code block
{
int
localVirable1 =
0;
final
int
localVirable2 =
1;
class
Inner1 {
public
Inner1() {
//can access its outer class' field and method directly
instanceField =
1;
//use OuterClass.this to get its corresponding outer class instance
Outer.
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 block
System.out.print(localVirable2);
}
}
//local class can not have privilege modifier
/*public class inner2 {
}*/
}
// define a local static member class in static code block
static
{
class
Inner2 {
public
Inner2() {
staticField =
1;
//can not access instance field and method in a local static member class
//intanceField = 2;
}
}
}
public
void
intanceMethod() {
//define a local class in its out class' instance method
class
Inner3 {
}
//local class is visible only in its containning code block
//Outer.Inner2 inner2;
}
private
static
void
staticMethod() {
//define a local static member class in its out class' static method
class
Inner4 {
public
Inner4() {
staticField =
2;
}
}
//can not define a interface as a local class
/*interface I {
}*/
}
}
3.1 局部类特性
如示例代码所示,局部类能且只能访问其所属代码段中的声明为 final 的局部
变量。为什么只能访问声明为 final 的局部变量呢?我们知道,局部变量在其所属的代码段(譬如某个函数)执行完毕后就会被回收,而一个局部类 的实例却可以在其类定义所属代码段执行完毕后依然存在,如果它可操控非 final 的局部变量,用户就可以通过该实例修改已不存在的局部变量,无意义。
3.2 局部类约束
如示例代码所示,内部类只在定义它的代码段中可见,不能在它所属代码段之外的代码中使用;因此也就没有 public/private/default 权限修饰符(无意义)
不能以局部类形式定义一个接口。局部类只在其所属代码段中可见,定义这样的接口无意义
局部类类名不能与其外部类类名重复
3.3 什么时候使用局部类
局部类大部分以匿名类的形式使用。
4 Anonymous class (匿名类)
没有类名的局部类就是匿名类。用一条语句完成匿名类的定义与实例创建。例
如如下代码:
public
class
Outer {
public
void
instanceMethod() {
//define a nonymous class which implements Action interface and creat an instance of it
Action action =
new
Action() {
public
void
doAction() {
System.out.println("a simple anonymous class demo");
}};
action.doAction();
//define a nonoymous class which extends BaseClass and create an instance of it
new
BaseClass(5) {
public
void
printData(){
System.out.println("data = "
+ getData());
}
}.printData();
//"data = 5" will be outputed
}
}
interface
Action {
void
doAction();
}
class
BaseClass {
private
int
data;
public
BaseClass (
int
data) {
this
.data = data;
}
public
int
getData() {
return
data;
}
}
4.1 匿名类特性与约束
匿名类是一种特殊的局部类。局部类的特性与约束都适用与它。
4.2 新增语法
4.2.1 继承自某个基类的匿名类
|
new class-name ( [ argument-list ] ) { class-body } |
创建匿名类实例时,“ argument-list” 将被传入其基类(即 class-name )对应的构造函数。
4.2.2 实现某个接口的匿名类
|
new interface-name () { class-body } |
4.3 什么时候使用匿名类
该类定义代码段很短
只需要创建该类的一个实例
类的定义代码与类的使用代码紧邻
使用匿名不影响代码的易读性
譬如,如下实现类似与 c 的 callback 功能的代码就是匿名类的典型应用:
File f =
new
File("/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(
new
FilenameFilter() {
public
boolean
accept(File f, String s) {
return
s.endsWith(".java"); }
});
// Don't forget the parenthesis and semicolon that end the method call!
1万+

被折叠的 条评论
为什么被折叠?



