参考链接: Java中的嵌套接口
java程序语言允许你在一个类里面再声明另一个类,这样的类成为嵌套类,说明如下:
class OuterClass {
...
class NestedClass {
...
}
}
术语:嵌套类分为两种:静态或非静态。嵌套类声明为static称为静态嵌套类。非静态嵌套类都称为内部类。
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
一个嵌套类是它的封装类的成员。非静态嵌套类可以访问它的封装类的其他成员,即使这些成员声明是private。静态嵌套类不能访问封装类的其他成员。就像外部类的一个成员一样,嵌套类可以声明为private,public,protected,包内私有(回顾外部类只能声明为public或者是包内私有)
为什么使用嵌套类
使用嵌套类,其中有几个令人信服的理由:
它是一个在一个地方使用类的逻辑分组的方法它加强封装嵌套类可以促进更可读性,可维护性的代码。
类的逻辑分组—如果一个类只是被其他一个类使用,那么合乎逻辑的是把它嵌套到该类,让这两个类在一起。嵌套这样的帮助类可以让包更加精简。
加强封装—考虑两个顶级类,A和B,如果B需要访问A的private成员,通过在A类隐藏B类,那么即使A的成员声明为private,那么B也可以访问它们。更多的是,B本身也可以隐藏于外部。
更可读性,可维护性的代码—在顶级类里嵌套小类,让代码更靠近使用的地方。
静态嵌套类
和类方法,类变量一样,一个静态嵌套类是和它的外部类关联的。就像静态类方法一样,一个静态嵌套类不能直接引用封装类的实例变量或者方法—它只能通过封装类的引用访问它们。
注意:一个静态嵌套类访问它的封装类(和其他类)的实例成员,就像访问其他顶级类一样。事实上,一个静态嵌套类就像一个顶级类,只是行为上嵌套在另一个顶级类里而已,达到打包方便的目的。
静态嵌套类是使用封装类的名字访问:
OuterClass.StaticNestedClass
例如,创建一个静态嵌套类的对象,语法是:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
内部类
如实例方法和实例字段一样,一个内部类是和封装类的实例关联的,并且可以直接访问这个对象的成员和方法。正是因为一个内部类是和实例关联的,所以它不能定义任何静态成员。
内部类的对象实例存在于外部类的实例,考虑下面的类:
class OuterClass {
...
class InnerClass {
...
}
}
一个内部类的实例,尽可以存在于外部类的实例中,并且可以直接访问封装实例的方法和字段。下图说明了这个想法:
一个内部类的实例存在于外部类的实例
实例化内部类之前,你首先要实例化外部类。然后基于外部类的对象创建内部类对象,语法是:
还有,有两种特别的内部类,局部类和匿名类(也可以成为匿名内部类)。这两者会在后面讨论。
内部类例子
为了演示内部类的使用,让我们思考一个数组。接下来的例子,我们会创建一个数组,填充为整数,输出的数组的索引值是升序的。
下面的DataStructure类包括:
DataStructure外部类,包含了添加整数到内部数组的方法,输出数组里的索引值InnerEvenIterator内部类,类似java的标准迭代器。迭代器用于遍历一个数据结果,典型的是判断是否到了最后一个元素,检索当前元素,移动到下一个元素。在main方法里实例化DataStructure对象,使用它填充数组arrayOfInts为一系列整数(0, 1, 2, 3, etc.),然后调用一个printEven 方法,输出arrayOfInts的索引值。
public class DataStructure {
// create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// fill the array with ascending integer values
for (int i = 0; i < SIZE; i ) {
arrayOfInts[i] = i;
}
}
public void printEven() {
// print out values of even indices of the array
InnerEvenIterator iterator = this.new InnerEvenIterator();
while (iterator.hasNext()) {
System.out.println(iterator.getNext() " ");
}
}
// inner class implements the Iterator pattern
private class InnerEvenIterator {
// start stepping through the array from the beginning
private int next = 0;
public boolean hasNext() {
// check if a current element is the last in the array
return (next <= SIZE - 1);
}
public int getNext() {
// record a value of an even index of the array
int retValue = arrayOfInts[next];
//get the next even element
next = 2;
return retValue;
}
}
public static void main(String s[]) {
// fill the array with integer values and print out only
// values of even indices
DataStructure ds = new DataStructure();
ds.printEven();
}
}
输出是:
0 2 4 6 8 10 12 14
注意InnerEvenIterator是直接引用DataStructure对象的实例变量arrayOfInts。
内部类可用来实现帮助类,就像上面的例子。如果你计划处理用户接口事件,你需要指导如何使用内部类,因为事件处理机制中,内部类是广泛使用的。
局部和匿名内部类
有两种良性的内部类。你可以在方法体内声明一个内部类。这样的类成为局部内部类。你也可以在方法体内,声明一个没有名字的内部类,这种类就是匿名内部类了。我们将会在java高级编程遇到它。
修饰符
可以为内部类使用修饰符,就像外部类成员那么使用。例如,可以使用特殊访问—private,public,protected—限制访问内部类的方式,就像和其他类成员的使用方式一样。