在类中您还可以定义类,称之为内部类(Inner class)或“巢状类”(Nested class)。非"static"的内部类可以分为三种:成员内部类(Member inner class)、区域内部类(Local inner class)与匿名内部类(Anonymous inner class)。 使用内部类的好处在于可以直接存取外部类的私用(private)成员,举个例子来说,在视窗程序中,您可以使用内部类来实现一个事件倾听者类,这个视窗倾听者类可以直接存取视窗组件,而不用透过参数传递。 另一个好处是,当某个Slave类完全只服务于一个Master类时,我们可以将之设定为内部类,如此使用Master类的人就不用知道 Slave的存在。 成员内部类是直接声明类为成员,例如: public class OuterClass {
// .... // 内部类 private class InnerClass { // .... } } 内部类同样也可以使用"public"、"protected"或"private"来修饰,通常声明为"private"的情况较多,下面这个程序简单示范成员内部类的使用:
public class OutClass { 上面的程序假设Point类只服务于OutClass类,所以使用OutClass时,不必知道Point类的存在,例如:
public class UseInnerClass { 区域内部类的使用与成员内部类类似,区域内部类定义于一个方法中,类的可视范围与生成之对象仅止于该方法之中,区域内部类的应用一般较为少见。 内部匿名类可以不声明类名称,而使用new直接产生一个对象,该对象可以是继承某个类或是实现某个接口,内部匿名类的声明方式如下: new [类或接口()] {
// 实现 } 一个使用内部匿名类的例子如下所示,您直接继承Object类来生成一个对象,并改写其toString()方法:
public class UseInnerClass { 执行结果:
注意如果要在内部匿名类中使用某个方法中的变量,它必须声明为"final",例如下面是无法通过编译的: ....
public void someMethod() { int x = 10; Object obj = new Object() { public String toString() { return "" + x; } }; System.out.println(obj.toString()); } 编译器会回报以下的错误: local variable x is accessed from within inner class; needs to be declared final
您要在 x 声明时加上final才可以通过编译: ....
public void someMethod() { final int x = 10; Object obj = new Object() { public String toString() { return "" + x; } }; System.out.println(obj.toString()); } 究其原因,在于 区域变量 x 并不是真正被拿来于内部匿名类中使用,而是在内部匿名类中复制一份,作为field成员来使用,由于是复本,即便您在内部匿名类中对 x 作了修改,会不会影响真正的区域变量 x,事实上您也通不过编译器的检查,因为编译器要求您加上"final"关键字,这样您就知道您不能在内部匿名类中改变 x 的值。 内部类还可以被声明为"static",不过由于是"static",它不能存取外部类的方法,而必须透过外部类所生成的对象来进行调用,一般来说较少使 用,一种情况是在main()中要使用某个内部类时,例如:
public class UseInnerClass { 由于main()方法是"static",为了要能使用Point类,该类也必须被声明为"static"。 被声明为static的内部类,事实上也可以看作是另一种名称空间的管理方式,例如: public class Outer {
public static class Inner { .... } .... } 您可以如以下的方式来使用Inner类: Outer.Inner inner = new Outer.Inner();
在文件管理方面,内部类在编译完成之后,所产生的文件名称为“外部类名称$内部类名称.class”,而内部匿名类则在编译完成之后产生“外部类名称$编号.class”,编号为1、2、3.....,看它是外部类中的第几个匿名类。 |