欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  Java

java中匿名内部类的构造方法调用

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

Java代码

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代码

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代码

class testtest.InnerTest$1 extends testtest.Test

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

Java代码

testtest.InnerTest$1(testtest.InnerTest, int);

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

Csharp代码

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><pre></pre>

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

先是

Csharp代码

0:  new #2; //class testtest/InnerTest$1

然后调用其构造方法:

Java代码

6: invokespecial #3; //Method testtest/InnerTest$1."〈init〉":(Ltesttest/InnerTest;I)V<pre></pre>

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


更多java中匿名内部类的构造方法调用相关文章请关注PHP中文网!

相关标签: 匿名内部类