内部类按照使用上可以分为四种情形:
类级:成员式,有 static 修饰 对象级:成员式,普通,无 static 修饰 本地内部类:局部式 匿名级:局部式内部类可以作为外部类的成员,示例如下: public class Outer1 { private int size; public class Inner { public void dostuff() { size++; } } public void testTheInner() { Inner in = new Inner(); in.dostuff(); } } 成员式内部类如同外部类的一个普通成员。
成员式内部类的基本规则:
可以有各种修饰符,可以用 4 种权限、static、final、abstract 定义(这点和普通 的类是不同的); 若有 static 限定,就为类级,否则为对象级。类级可以通过外部类直接访问;对象级需要先生成外部的对象后才能访问。 内外部类不能同名 非静态内部类中不能声明任何 static 成员 内部类可以互相调用,如下: class A { // B、C 间可以互相调用 class B {} class C {} }成员式内部类的访问 内部类的对象以属性的方式记录其所依赖的外层类对象的引用,因而可以找到该外层类对象并访问其成员 。 该属性是系统自动为非static的内部类添加的,名称约定为“外层类名.this”。
在其它场合则必须先获得外部类的对象,再由外部类对象加“.new”操作符调用内部类的构造方法创建内部类的对象,此时依赖关系的双方也可以明确。这样要求是因为:外部类的static 方法中不存在当前对象,或者其它无关类中方法的当前对象类型不符合要求。
(1)在另一个外部类中使用非静态内部类中定义的方法时,要先创建外部类的对象,再创建与外部类相关的内部类的对象,再调用内部类的方法,如下所示: class Outer2 { private int size; class Inner { public void dostuff() { size++; } } } class TestInner { public static void main(String[] args) { Outer2 outer = new Outer2(); Outer2.Inner inner = outer.new Inner(); inner.dostuff(); } }
(2)static 内部类相当于其外部类的 static 成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。示例如下: class Outer2 { private static int size; static class Inner { public void dostuff() { size++; System.out.println(“size=” + size); } } } public class Test { public static void main(String[] args) { Outer2.Inner inner = new Outer2.Inner(); inner.dostuff(); } } 程序运行结果为: size=1
(3)由于内部类可以直接访问其外部类的成分,因此当内部类与其外部类中存在同名属性或方法时,也将导致命名冲突。所以在多层调用时要指明,如下所示: public class Outer3{ private int size; public class Inner{ private int size; public void dostuff(int size){ size++; // 本地的 size; this.size; // 内部类的 size Outer3.this.size++; // 外部类的 size } } }
本地类(Local class)是定义在代码块中的类。它们只在定义它们的代码块中是可见的。
本地类有几个重要特性:
仅在定义了它们的代码块中是可见的; 可以使用定义它们的代码块中的任何本地 final 变量; 本地类不可以是 static 的,里边也不能定义 static 成员; 本地类不可以用 public、private、protected 修饰,只能使用缺省的; 本地类可以是 abstract 的。示例如下: public final class Outter { public static final int TOTAL_NUMBER = 5; public int id = 123; public void t1() { final int a = 15; String s = “t1″; class Inner { public void innerTest() { System.out.println(TOTAL_NUMBER); System.out.println(id); System.out.println(a); // System.out.println(s);不合法,只能访问本地方法的final变量 } } new Inner().innerTest(); } public static void main(String[] args) { Outter t = new Outter(); t.t1(); } }
匿名内部类是本地内部类的一种特殊形式,也就是没有变量名指向这个类实例,而且具体的类实现会写在这个内部类里面。把上面的例子改造一下,如下所示: public final class Test { public static final int TOTAL_NUMBER = 5; public int id = 123; public void t1() { final int a = 15; String s = “t1″; new Aclass() { public void testA() { System.out.println(TOTAL_NUMBER); System.out.println(id); System.out.println(a); // System.out.println(s);不合法,只能访问本地方法的final变量 } }.testA(); } public static void main(String[] args) { Test t = new Test(); t.t1(); } } 注意:匿名内部类是在一个语句里面,所以后面需要加“;”。
匿名类的规则:
匿名类没有构造方法; 匿名类不能定义静态的成员; 匿名类不能用 4 种权限、static、final、abstract 修饰; 只可以创建一个匿名类实例再次示例: public class Outter { public Contents getCont() { return new Contents() { private int i = 11; public int value() { return i; } }; } public static void main(String[] args) { Outter p = new Outter(); Contents c = p.getCont(); } }
总结一下,内部类有如下特点:
类名称只能用在定义过的范围中,除非用在限定的名称中。内部类的名称必须与所嵌套的类不同。 内部类可以被定义在方法中。这条规则较简单,它支配到所嵌套类方法的变量的访问。任何变量,不论是本地变量还是正式参数,如果变量被标记为final,那么,就可以被内部类中的方法访问。 内部类可以使用所嵌套类的类变量和实例变量以及所嵌套的块中的本地变量。 内部类可以被定义为 abstract。 只有内部类可以被声明为 private 或 protected,以便防护它们不受来自外部类的访问。访问保护不阻止内部类使用其它类的任何成员,只要一个类嵌套另一个。 一个内部类可以作为一个接口,由另一个内部类实现。 被自动地声明为 static 的内部类成为顶层类。这些内部类失去了在本地范围和其它内部类中使用数据或变量的能力。 内部类不能声明任何 static 成员;只有顶层类可以声明 static 成员。因此,一个需求 static 成员的内部类必须使用来自顶层类的成员。