
3.6 内部类
在一个类的内部我们还可以定义类,这就是内部类,也称为嵌套类。内部类的定义范围要比包小,它定义在另一个类里面,也可以定义在一个方法里面,甚至可以定义在一个表达式中。与内部类相对而言,包含内部类的类称为外部类或顶级类。
内部类本身是一个类,但它同时又是外部类的一个成员。作为外部类的成员,它可以毫无限制地访问外部类的变量和方法,包括private成员。这和private的含义并不矛盾,因为private修饰符只是限制从一个类的外部访问该类成员的权限,而内部类在外部类内部,所以它可以访问外部类的所有资源。
内部类又具有多种形式,可细分为:静态内部类、成员内部类、本地内部类和匿名内部类。在一个顶级类中声明一个类,并用static修饰符修饰的该类,就是静态内部类。例如:
package mypackage; public class OuterClass { ... public static class StaticInnerClass { ... } }
该例中静态内部类的完全限定名称为mypackage.OuterClass.StaticInnerClass,编译时Java产生两个class文件:OuterClass.class和OuterClass$StaticInnerClass.class。静态内部类作为外部类的静态成员,和其他静态变量、静态方法一样,与对象无关,静态内部类只可以访问外部类的静态变量和静态方法,而不能直接引用定义在外部类中的实例变量或者方法,但可以通过对象的引用来使用它们。
匿名内部类是没有名字的内部类。由于匿名内部类没有名称,在程序中没有办法引用它们。在Java中,创建匿名内部类对象的语法如下:
new 类或接口() {类的主体}
这种形式的new语句声明一个匿名内部类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建匿名内部类的一个对象实例,并把这个对象实例作为new语句的返回值。在Java程序中,匿名内部类的使用十分广泛,它常被用来实现某个接口。例如实现Enumeration接口(它定义在java.util包中),Enumeration接口提供了方法,用来遍历集合数据结构的每个成员,而不暴露集合对象本身。
下面通过一个例子来说明匿名内部类的用法,该例子实现了一个简单的动态数组。
例3.16 JDynamicArray.java
import java.util.Enumeration; public class JDynamicArray{ private Object[] array = null; private int count = 0; public JDynamicArray(int size) { if (size <= 0) { throw new IllegalArgumentException("size must > 0"); } array = new Object[size]; } public int add(Object obj) { if (count == array.length) { Object[] newArray = new Object[array.length * 2 + 1]; for (int i = 0; i < array.length; i++) { newArray[i] = array[i]; } array = newArray; } array[count++] = obj; return count; } public Enumeration getEnumeration() { //匿名内部类实现Enumeration接口 return new Enumeration() { private int index = 0; public boolean hasMoreElements() { return index < count; } public Object nextElement() { return array[index++]; } }; } public static void main(String[] args) { JDynamicArray da = new JDynamicArray(10); for(int i=0; i<10; i++) { da.add(new Integer(i)); } for (Enumeration e = da.getEnumeration(); e.hasMoreElements(); ) { System.out.println(e.nextElement()); } } }
程序运行结果:
0 1 ... 9