arcel8 { // Argument must be final to use inside // anonymous inner class: public Destination dest(final String dest) { return new Destination() { private String label = dest; public String readLabel() { return label; } }; ? ? } public static void main(String[] args) { Parcel8 p = new Parcel8(); Destination d = p.dest("Tanzania"); ? ? } } 如果你有一个匿名内部类,它要使用一个在它的外部定义的对象,编译器会要求其参数引用是final 型的,就像dest()中的参数。如果你忘记了,会得到一个编译期错误信息。如果只是简单地给一个成员变量赋值,那么此例中的方法就可以了。但是,如果你想做一些类似构造器的行为,该怎么办呢?在匿名类中不可能有已命名的构造器(因为它根本没名字!),但通过实例初始化,你就能够达到为匿名内部类“制作”一个构造器的效果。像这样做: abstract class Base { public Base(int i) { System.out.println("Base constructor, i = " + i); ? ? } public abstract void f(); } ? public class AnonymousConstructor { public static Base getBase(int i) { return new Base(i) { ? ? ? ? ? ? { System.out.println("Inside instance initializer"); ? ? ? ? ? ? } public void f() { System.out.println("In anonymous f()"); ? ? ? ? ? ? } }; ? ? } public static void main(String[] args) { Base base = getBase(47); base.f(); ? ? } } 在此例中,不要求变量i 一定是final 的。因为i 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。下例是带实例初始化的“parcel”形式。注意dest()的参数必须是final,因为它们是在匿名类内被使用的。 public class Parcel9 { public Destinationdest(final String dest, final float price) { return new Destination() { private int cost; // Instance initialization for each object: ? ? ? ? ? ? { cost = Math.round(price); if(cost > 100) System.out.println("Over budget!"); ? ? ? ? ? ? } ? private String label = dest; public String readLabel() { return label; } }; ? ? } public static void main(String[] args) { Parcel9 p = new Parcel9(); Destination d = p.dest("Tanzania", 101.395F); ? ? } } 在实例初始化的部分,你可以看到有一段代码,那原本是不能作为成员变量初始化的一部分而执行的(就是if 语句)。所以对于匿名类而言,实例初始化的实际效果就是构造器。当然它受到了限制:你不能重载实例初始化,所以你只能有一个构造器。 ? ? ? ? ? 从多层嵌套类中访问外部 一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员,如下所示: class MNA { private void f() {} class A { private void g() {} public class B { void h() { g(); f(); ? ? ? ? ? ? } ? ? ? ? } ? ? } } public class MultiNestingAccess { public static void main(String[] args) { MNA mna = new MNA(); MNA.A mnaa = mna.new A(); MNA.A.B mnaab = mnaa.new B(); mnaab.h(); ? ? } } 可以看到在MNA.A.B中,调用方法g()和f()不需要任何条件(即使它们被定义为private)。这个例子同时展示了如何从不同的类里面创建多层嵌套的内部类对象的基本语法。“.new”语法能产生正确的作用域,所以你不必在调用构造器时限定类名。 ? ? ? ? ? 内部类的重载问题 ? 如果你创建了一个内部类,然后继承其外围类并重新定义此内部类时,会发生什么呢?也就是说,内部类可以被重载吗?这看起来似乎是个很有用的点子,但是“重载”内部类就好像它是外围类的一个方法,其实并不起什么作用: ? class Egg { ? ? ? private Yolk y; ? ? ? ? protectedclass Yolk { ? ? ? ? ? ? ? public Yolk() { ? ? ? ? ? ? ? ? ? ? System.out.println("Egg.Yolk()"); ? ? ? ? ? ? ? } ? ? ? } ? ? ? ? public Egg() { ? ? ? ? ? ? ? System.out.println("New Egg()"); ? ? ? ? ? ? ? y = new Yolk(); ? ? ? } } ? publicclass BigEgg extends Egg { ? ? ? publicclass Yolk { ? ? ? ? ? ? ? public Yolk() { ? ? ? ? ? ? ? ? ? ? System.out.println("BigEgg.Yolk()"); ? ? ? ? ? ? ? } ? ? ? } ? ? ? ? publicstaticvoid main(String[] args) { ? ? ? ? ? ? ? new BigEgg(); ? ? ? } } ? ? 输出结果为: New Egg() Egg.Yolk() ? 缺省的构造器是编译器自动生成的,这里是调用基类的缺省构造器。你可能认为既然创建了BigEgg 的对象,那么所使用的应该是被“重载”过的Yolk,但你可以从输出中看到实际情况并不是这样的。 这个例子说明,当你继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。当然,明确地继承某个内部类也是可以的: ? class Egg2 { ? ? ? protected class Yolk { ? ? ? ? ? ? ? public Yolk() { ? ? ? ? ? ? ? ? ? ? System.out.println("Egg2.Yolk()"); ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? public void f() { ? ? ? ? ? ? ? ? ? ? System.out.println("Egg2.Yolk.f()"); ? ? ? ? ? ? ? } ? ? ? } ? ? ? ? private Yolk y = new Yolk(); ? ? ? ? public Egg2() { ? ? ? ? ? ? ? System.out.println("New Egg2()"); ? ? ? } ? ? ? ? public void insertYolk(Yolk yy) { ? ? ? ? ? ? ? y = yy; ? ? ? } ? ? ? ? public void g() { ? ? ? ? ? ? ? y.f(); ? ? ? } } ? public class BigEgg2 extends Eg |