内部类就是一种链关系,就好像C++当中的指针一样,或者这是一个指向具体内容的指针,或者这是一个指向指针的指针,看看下面的代码:class Outer1{ class Inner11{ class Inner111{ int var111 = 100; } } class Inner12{ class Inner121{ int var121 = 10; class Inner1211{ int var1211 = Outer1.Inner12.Inner121.this.var121; } } }}
public class OutClass1{ public static void main(String[] args){ int var1 = new Outer1().new Inner11().new Inner111().var111; int var2 = new Outer1().new Inner12().new Inner121().new Inner1211().var1211; System.out.println(var1); System.out.println(var2); }}这里的内部类嵌套了内部类,一层层的,很容易看出来就好像一种链接关系,就好像数据结构当中的树,层次分明。要注意的一个地方就是关于var1211的赋值,首先要说的就是要
找到上一级的变量,只要逐层找就可以了,还有就是因为上一层变量在赋值的时候要加上this.var121,因为要赋值的是上一层变量的实例变量。而this的使用则是,this放在哪个
类后,就说明该this是该类的实例。如果内部类是static的,那么就不需要这样一层一层的new了,它的使用方法,就好像普通的static一样,如果是逐层的static,那么要到最里层的静态变量,就好像普通的静态变
量一样,只不过多了一些指向的标识符而已。如果静态变量中间夹杂了非静态变量,那么该new的时候,就实例化,该直接用的时候,就直接用就可以了。
内部类的继承要调用父类的外层类的super(),下面看一下下面的代码:class Outer2{ class Inner21{ }}
class Outer3{ class Inner31 extends Outer2.Inner21{ Inner31(Outer2 o2){ o2.super(); } }}试试把构造函数注释掉,或者只注释o2.super(),看看是否能编译过去。
内部类可以使用外层类,但是,如果需要生成一个实例才有内部类,就不能通过编译了。也可以这样说,内部类可以写在外部类的函数中,但是,如果写到函数中,就不能在外层
类使用了,下面看一个例子:class Outer3{ void prtOuter3(){ System.out.println("Outer3"); } class Inner31{ Inner31(){ class Inner311{ void prtInner31(){ System.out.println("Inner311"); } void prtprtInner31(){ Outer3.this.prtOuter3(); } } } }}
public class OuterClass3{ public static void main(String[] args){ Outer3.Inner31.Inner311 inner = new Outer3().new Inner31().new Inner311(); inner.prtprtInner31(); }}上面这段代码是不能通过编译的,就是因为它把内部类写到了外层类的函数中之后,还想在外部使用它,想要通过编译(这里说的只是通过编译,没有说使用的意图),有两个方法
可以,一个是将内部类移到构造方法外,另外一个就是不要在main方法当中实例该内部类。
又是外层,又是同层,又是内部类,写着写着万一重名了字母办(只是假设,很少有机会写这么多内部类,还有内部类嵌套内部类吧,如果出现这样的情况,首先要想的应该是,我
的设计是不是有问题?)?那么到底该调用哪个类呢,通过下面的例子,就能说明这样的情况。class Outer4{ { new Inner42(); } class Inner41{ { System.out.println("Outer4.Inner41"); } } class Inner42{ { new Inner41(); } class Inner41{ { System.out.println("Outer4.Inner42.Inner41"); } } }}
public class OuterClass4{ public static void main(String[] args){ new Outer4(); }}这时候出现了两个同名的类,一个是Inner42的内部类Inner41,一个是它的同级别的类,那么这时候要在Inner42里面实例化Inner41,会出现什么样的结果呢,是不会通过编译,
还是什么,运行一下,可以通过编译,得出的是Outer4.Inner42.Inner41,所以得出结论,如果同名,内部类优先,那么如果我想使用的是同级类呢,这也很简单,加上前面讲的
链new Outer4.Inner41()就可以了。所以也可以看出来,在链接的过程,不要出现同名,也就是说内部类的名字可以与该类的同级别类同名,但是不能在该链上出现同名。比如:class Outer{ class Inner1{ class Inner11{ //class Outer{}如果去掉注释就会出错 } }}这时候就不允许出现重名。
下面就是包含了一个内部类,内部接口,匿名类的例子,首先要说明的是,匿名内部类不像内部类那样,可以有构造函数,它不能有构造函数,所以只能通过块{}来初始化:interface OuterInterface{ int varInterface = 1; void pt();}
class Outer51{ Outer51(){ } int get(){ return 100; }}
class Outer52{ /*interface OuterInterface{ void pt(); }*/ class Inner521{ OuterInterface testMthodInterface(){ final int i = 2; int j = 3; return new OuterInterface(){ int k; { k = i+k; } public void pt(){ System.out.println(k); } }; } Outer51 testMethodClass(){ return new Outer51(){ public int get(){ return super.get()*10; } }; } }}
public class OuterClass5{ public static void main(String[] args){ int v1 = new Outer52().new Inner521().testMethodClass().get(); System.out.println(v1); new Outer52().new Inner521().testMthodInterface().pt(); }}从这里,就可以看出,继承接口内部优先。匿名内部类同普通类一样,可以继承自接口,也可以继承自类,继承自类的构造函数中,可以有参数。
接口可以嵌套在接口中,也可以嵌套在类的顶层中,但是不能嵌套在内部类中,看一下下面的代码:class OuterClass{ interface InnerInterface{} class InnerClass{ //interface InnerInterface{} }}如果去掉注释,就不能通过编译了。
ps:看到一篇关于内部类的总结(http://www.newasp.net/tech/java/14908.html),觉得总结的不错,揣摩了一下,用自己的话总结了一下。