JAVA匿名内部类的构造方法

与人讨论匿名内部类的构造方法问题,自己写代码看看原理到底是什么样子的。因为类是匿名的,所以就无从创建一个同名的构造方法了。但是可以直接调用父类的构造方法。测试代码如下:

 

Java代码 复制代码  收藏代码
  1. package testtest;   
  2.   
  3. public class Main {   
  4.   
  5.     public static void main(String[] args) {   
  6.         InnerTest inner = new InnerTest();   
  7.         Test t = inner.get(3);   
  8.         System.out.println(t.getI());   
  9.     }   
  10. }   
  11.   
  12. class Test {   
  13.   
  14.     private int i;   
  15.   
  16.     public Test(int i) {   
  17.         this.i = i;   
  18.     }   
  19.   
  20.     public int getI() {   
  21.         return i;   
  22.     }   
  23. }   
  24.   
  25. class InnerTest {   
  26.   
  27.     public Test get(int x) {   
  28.         return new Test(x) {   
  29.   
  30.             @Override  
  31.             public int getI() {   
  32.                 return super.getI() * 10;   
  33.             }   
  34.         };   
  35.     }   
  36. }  
package testtest;

public class Main {

    public static void main(String[] args) {
        InnerTest inner = new InnerTest();
        Test t = inner.get(3);
        System.out.println(t.getI());
    }
}

class Test {

    private int i;

    public Test(int i) {
        this.i = i;
    }

    public int getI() {
        return i;
    }
}

class InnerTest {

    public Test get(int x) {
        return new Test(x) {

            @Override
            public int getI() {
                return super.getI() * 10;
            }
        };
    }
}

编译之后得到4个class文件:Test.class,InnerTest.class,InnerTest$1.class以及Main.class。容易看出来,Main.class是测试类的class文件,Test.class是超类Test的class文件,InnerTest.class是InnerTest 的class文件,最值得关注的就是匿名内部类的class文件InnerTest$1.class。

首先javap -c InnerTest$1

 

Java代码 复制代码  收藏代码
  1. Compiled from "Main.java"  
  2. class testtest.InnerTest$1 extends testtest.Test{   
  3. final testtest.InnerTest this$0;   
  4.   
  5. testtest.InnerTest$1(testtest.InnerTest, int);   
  6.   Code:   
  7.    0:   aload_0   
  8.    1:   aload_1   
  9.    2:   putfield    #1//Field this$0:Ltesttest/InnerTest;   
  10.    5:   aload_0   
  11.    6:   iload_2   
  12.    7:   invokespecial   #2//Method testtest/Test."<init>〈init〉":(I)V   
  13.    10:  return  
  14.   
  15. public int getI();   
  16.   Code:   
  17.    0:   aload_0   
  18.    1:   invokespecial   #3//Method testtest/Test.getI:()I   
  19.    4:   bipush  10  
  20.    6:   imul   
  21.    7:   ireturn   
  22.   
  23. }   
  24.   
  25. </init>  
Compiled from "Main.java"
class testtest.InnerTest$1 extends testtest.Test{
final testtest.InnerTest this$0;

testtest.InnerTest$1(testtest.InnerTest, int);
  Code:
   0:	aload_0
   1:	aload_1
   2:	putfield	#1; //Field this$0:Ltesttest/InnerTest;
   5:	aload_0
   6:	iload_2
   7:	invokespecial	#2; //Method testtest/Test."<init>〈init〉":(I)V
   10:	return

public int getI();
  Code:
   0:	aload_0
   1:	invokespecial	#3; //Method testtest/Test.getI:()I
   4:	bipush	10
   6:	imul
   7:	ireturn

}

</init>

很明显,虽然我们看来是匿名内部类,但编译的时候给这个类指定了名字

InnerTest$1,而且看出来是继承自Test:

Java代码 复制代码  收藏代码
  1. class testtest.InnerTest$1 extends testtest.Test  
class testtest.InnerTest$1 extends testtest.Test

而且在这个类有构造方法: 

Java代码 复制代码  收藏代码
  1. testtest.InnerTest$1(testtest.InnerTest, int);  
testtest.InnerTest$1(testtest.InnerTest, int);

这里也很容易理解,两个参数,一个是匿名内部类的外部类引用直接传了进来,这也是我们能在内部类中直接访问外部类成员的实现原理。另外一个就是int类型的参数了。也就是说其实编译器自动的给我们添加了带参数的构造方法。继续往下看: 
7: invokespecial #2; //Method testtest/Test."<init>":(I)V
这就是调用父类的构造方法了 。
接下来 ,我们 只要看 InnerTest中 get方法 的 实现就可以了 :

Csharp代码 复制代码  收藏代码
  1. Compiled from "Main.java"  
  2. class testtest.InnerTest extends java.lang.Object{   
  3. testtest.InnerTest();   
  4.   Code:   
  5.    0:   aload_0   
  6.    1:   invokespecial   #1; //Method java/lang/Object."<init>〈init〉":()V   
  7.    4:   return  
  8.   
  9. public testtest.Test get(int);   
  10.   Code:   
  11.    0:   new #2; //class testtest/InnerTest$1   
  12.    3:   dup   
  13.    4:   aload_0   
  14.    5:   iload_1   
  15.    6:   invokespecial   #3; //Method testtest/InnerTest$1."<init>〈init〉":(Ltesttest/InnerTest;I)V   
  16.    9:   areturn   
  17.   
  18. }   
  19. </init></init><PRE></PRE>  
Compiled from "Main.java"
class testtest.InnerTest extends java.lang.Object{
testtest.InnerTest();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>〈init〉":()V
   4:	return

public testtest.Test get(int);
  Code:
   0:	new	#2; //class testtest/InnerTest$1
   3:	dup
   4:	aload_0
   5:	iload_1
   6:	invokespecial	#3; //Method testtest/InnerTest$1."<init>〈init〉":(Ltesttest/InnerTest;I)V
   9:	areturn

}
</init></init>


到这里一切都清楚了,InnerTest中对待匿名内部类和对待普通类一样,

先是

Csharp代码 复制代码  收藏代码
  1. 0:  new #2; //class testtest/InnerTest$1  
0:	new	#2; //class testtest/InnerTest$1

然后调用其构造方法:

Java代码 复制代码  收藏代码
  1. 6: invokespecial #3//Method testtest/InnerTest$1."〈init〉":(Ltesttest/InnerTest;I)V<PRE></PRE>  
6: invokespecial #3; //Method testtest/InnerTest$1."〈init〉":(Ltesttest/InnerTest;I)V


<init></init><init>OK,一切都清楚了 。<br></init>

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值