3 内部类
内部类是 Java 中很特殊的一个语法。一方面,内部类能够一定程度上的减少代码量,并且能够为程序员提供一些语法方面的比较方便的功能。另一方面来说,内部类有可能带来非常古怪的语法,这些语法会造成代码的可读性下降。因此,内部类是一把双刃剑。从规范上说,我们并不提倡程序员过多的使用内部类,不过依然应该了解一些内部类的基本语法和部分内部类的使用方法。
Java 中的内部类分为四种:成员内部类、静态内部类、局部内部类、匿名内部类,我们下面对这四种内部类分别进行介绍。
3.1 成员内部类
class MyOuterClass{ private int value; private class InnerClass{ public void m(){ System.out.println(value); } } }
上面这段代码演示了如何定义一个成员内部类。
首先,定义成员内部类的位置,应该在某一个类的里面,在任何一个函数的外面(也就是定义成员变量的位置)。
其次,由于成员内部类定义在外部类的内部,因此在成员内部类中可以访问外部类的私有成员。例如,上面的程序中,在 InnerClass 的 m 方法中,就访问了外部类 MyOuterClass的私有属性 value。
第三,成员内部类可以作为 private 的。之前我们学习修饰符的时候曾经提过,private不能修饰类。但是 private 可以修饰成员内部类,这表示只能在 MyOuterClass 的内部使用InnerClass 类。
编译上面的程序,会在相应的目录中生成两个.class 文件:一个 MyOuterClass.class 文件和一个MyOuterClass$InnerClass.class 文件。这说明,在编译时,内部类也会生成独立的.class文件,换句话说,内部类也是独立的类。
最后要说明的一点,由于成员内部类必须与外部类某一个对象相关联,因此成员内部类中不能定义静态方法。
3.2 静态内部类
静态内部类与成员内部类相似,只有一点不同:在定义成员内部类之前,增加一个 static关键字,则定义的内部类就成为一个静态内部类。示例代码如下:
class MyOuterClass{ //成员内部类 class MemberInner{} //静态内部类 static class StaticInner{} }
需要说明的是,static 关键字不能够用来修饰类,但是能够用来修饰内部类。接下来我们看一下静态内部类以及成员内部类对外部类成员的访问。
class MyOuterClass{ int value1 = 100; public void m1(){} static int value2 = 200; public static void m2(){} class InnerClass1{ public void f1(){ //成员内部类中能够访问外部类的静态成员以及非静态成员 System.out.println(value1); System.out.println(value2); m1(); m2(); } //!public static void f2(){} //编译出错,成员内部类不能定义静态方法 } static class InnerClass2{ public void f1(){ //静态内部类中只能访问外部类的静态成员 //System.out.println(value1); 出错! System.out.println(value2); //! m1(); m2(); } //静态内部类中可以定义静态方法 public static void f2(){} } }
成员内部类中不能定义静态方法;成员内部类中能够访问外部类的所有静态以及非静态的成员;
静态内部类中可以定义静态方法,静态内部类中只能访问外部类的静态成员(即访问外部类的静态属性或者调用外部类的静态方法。)
至于如何创建静态内部类的对象,也分两种情况
第一种情况,在外部类中,可以直接创建内部类的对象。(在上面的例子中,指的是在MyOuterClass 类中,可以直接创建内部类的对象)。这种情况与成员内部类的情况相同,在此不再赘述。
第二种情况,在外部类的外部创建对象。以上面的例子来说,也就是在 MyOuterClass类的外部如何创建内部类对象。这种情况下,静态内部类比成员内部类要简单的多。直接使用“外部类.内部类”的方式就能够创建。
3.3 局部内部类
所谓局部内部类,指的是定义在方法内部的类。
class Outer{ private int value = 100; private static int value2 = 200; public void m(){ int localValue = 300; class Inner{ public void f(){ System.out.println(value); System.out.println(value2); } } Inner in = new Inner(); in.f(); } }
与局部变量一样,局部内部类访问范围就是在方法内部。也就是说,定义的这个 Inner类只能在 m 方法内部使用,而无法在 m 方法外部使用。
3.4 匿名内部类
匿名内部类是一种特殊的局部内部类。如果一个局部内部类满足这样两个特点:
1、该内部类继承自某个类或者实现某个接口;
2、该内部类在整个方法中只创建了一个对象。满足这两个特点的局部内部类就能够改写成匿名内部类。
public static Teacher getTeacher(int n){ //Jim 依然采用局部内部类的写法 class Jim implements Teacher{ public void teach(){ System.out.println(“Jim teach”); } } //匿名内部类 if (n == 10) return new Teacher(){ public void teach(){ System.out.println(“Tom teach”); } }; else return new Jim(); }