我们一般使用的java内部类有4种形式:一般内部类、局部内部类、匿名内部类、静态内部类。以下是我作的一个测试,以说明各种内部类的特性。
/* * java内部类测试 * * InterObj反射结果: * * private int i * private InterObj$InterA ia * public InterObj() * public static void main(java.lang.String[]) * private int getI() * public void p() * public void pi() * public void pp() * public static void ppp() * public void pppp() * 下面是编译器自动生成用于访问私有属性或方法package级别的static方法 * static int access$0(InterObj) */ public class InterObj { private int i=8; private InterA ia=null;
public InterObj(){ ia=new InterA(); }
private int getI(){ return i; }
public void p(){ pi(); pp(); ppp(); pppp(); }
/* * 在一般内部类中可以访问“外套类”中的任何级别的方法和属性。而外套类也同样可以 * 访问“内部类”中的任何级别的方法和属性。因为内部类可以持有对外套类对象的引用。 * 而“外套类”对于自己的需要被内部类访问的私有方法和属性,编译器都会自动生成与 * 私有方法和属性相对应的“package”级别的static方法,这些方法需要用外部类对象作 * 为参数,这样就可以在“package”级别的static方法中通过访问外套类中的私有方法和 * 属性了。 * 而对于外套类要访问内部类中的私有方法和属性,也是同样的原理,内部类在编译时, * 会生成与需要被外套类访问的私有方法、属性相对应的“package”级别的static方法。 * * InterA反射结果: * private int ia * 下面是内部类持有的外套类对象引用 * final InterObj this$0 * 构造函数中用外套类对象作为参数 * InterObj$InterA(InterObj) * private void pA() * 下面是编译器自动生成用于访问私有属性或方法package级别的static方法 * static void access$0(InterObj$InterA) * public void pA1() * */ class InterA{ private int ia=9; private void pA(){ System.out.println("this is InterA.pA: ia="+ia+",InterObj.i="+getI()); } public void pA1(){ System.out.println("this is InterA.pA1: ia="+ia+",InterObj.i="+getI()); } }
/* * 局部内部类,只在方法内部可见,其它特性与一般内部类相同。 * 对需要访问的局部变量,必需设置成final,因为局部内部类虽然可以持有对外套类对象的 * 引用来访问外部类的属性和方法,但是却不能访问外部类方法中局部变量,所有编译器就 * 在局部内部类中“拷贝”了一份需要访问的局部变量(但是对于基本类型int,float和String * 等值不发生改变的类型没有拷贝)为了保证拷贝的变量值和外部方法中的变量的值所指向的 * 对象是同一 个对象,所以要求那些被局部类使用的局部变量应该设置成final,而不能被修 * 改,这样来保证局部内中拷贝的变量和外部方法中的变量所指向的是同一个对象。变量设 * 置成final只是控制变量指向的对象地址不变,而不是它指向的对象的内部属性不能改变。 * * InterB的反射结果: * * private int ib * 下面是内部类持有的外套类对象引用 * final InterObj this$0 * 下面是内部类持有的外部方法中的局部变量Test对象的引用拷贝 * private final Test val$test * 构造函数中用外套类对象和局部变量Test作为参数 * InterObj$1$InterB(InterObj,Test) * private void pB() * 下面是编译器自动生成用于访问私有属性或方法package级别的static方法 * static void access$0(InterObj$1$InterB) */ public void pi(){ final int s=5; final Test test=new Test(); class InterB{ private int ib=7; private void pB(){ System.out.println("this is InterB.pB: ib="+ib+ ",(Method)pi.s="+s+",Test.t="+test.getT()); } } InterB ib=new InterB(); //此处改变了被局部内部类引用了的Test test的内部状态。 //结果调用ib.pB()时,输出的就是改变后的值100 test.setT(100); ib.pB(); }
/* * 静态内部类,在不需要持有对“外套类对象”的引用时使用。 * * InterC反射结果:(静态内部类没有对外套类对象的引用) * private int ic * InterC() * private void pC() */ static class InterC{ private int ic=6; private void pC(){ System.out.println("this is InterC.pC: ic="+ic); } }
/* * 非静态方法,可以构造静态和非静态的内部类。 * 可以访问内部类中任何权限的属性和方法 */ public void pp(){ InterA ia=new InterA(); ia.pA(); ia.pA1(); InterC ic=new InterC(); ic.pC(); //局部内部类,只在方法内部可见 //InterB ib=new InterB(); }
/* * 静态方法,只能构造静态的内部类。 * 不能构造非静态的内部类,因为静态方法中没有this来引用“外套类”的对象,来构造 * 需要引用外套类对象引用的内部类对象。 */ public static void ppp(){ //InterA ia=new InterA(); //但是可以如下构造: InterObj iobj=new InterObj(); InterA ia=iobj.new InterA(); ia.pA(); ia.pA1(); InterC ic=new InterC(); ic.pC(); //局部内部类,只在方法内部可见 //InterB ib=new InterB(); }
/* * 匿名内部类测试 */ public void pppp(){ TestInterface tif=new TestInterface(){ public void pppp() { System.out.println("TestInterface.noName"); } }; tif.pppp(); }
/* * 运行结果: * this is InterB.pB: ib=7,(Method)pi.s=5,Test.t=100 * this is InterA.pA: ia=9,InterObj.i=8 * this is InterA.pA1: ia=9,InterObj.i=8 * this is InterC.pC: ic=6 * this is InterA.pA: ia=9,InterObj.i=8 * this is InterA.pA1: ia=9,InterObj.i=8 * this is InterC.pC: ic=6 * TestInterface.noName */ public static void main(String[] args) { InterObj io=new InterObj(); io.p(); } }
/* * 用于创建内部类的接口 */ interface TestInterface{ public void pppp(); }
/* * 用于测试局部内部类的局部变量类 */ class Test{ private int t=9; public int getT(){ return t; } public void setT(int t1){ t=t1; } }
|