内部类就是一种链关系,就好像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),觉得总结的不错,揣摩了一下,用自己的话总结了一下。