---------------------- <a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net培训</a>、期待与您交流! ----------------------
我在上一篇博客中说到匿名内部类,里面提到一句话,说匿名内部类是没有构造函数的,但是却可以实例化一个对象,这是百度的,我第一次看到这句话时楞了一下,为什么呢?没有构造函数,拿什么区创建实例呢?
查了查,原来是因为匿名内部类连名字的都没有,怎么会有构造函数呢,总不能写一对括号吧,后来想想内部类其实类似父子类,既然继承父类,肯定得调用父类的构造函数啦,于是我就在网上查了一篇博客,地址是http://zangxt.iteye.com/blog/421560,里面就举例说明了匿名内部类调用父类的构造函数,内容我就直接拿过来了:
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:
- class testtest.InnerTest$1 extends testtest.Test
而且在这个类有构造方法:
- 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中对待匿名内部类和对待普通类一样,先是
- 0: new #2; //class testtest/InnerTest$1
然后调用其构造方法:
- 6: invokespecial #3; //Method testtest/InnerTest$1."〈init〉":(Ltesttest/InnerTest;I)V<pre></pre>
但如果匿名内部类是实现的一个接口呢?接口也是没有构造函数的,为什么呢?因为接口没有具体的实现啊,
如果有构造函数就不算接口了,而是一个抽象函数,so,这下子父类也没有构造函数了,匿名内部类调用谁去?
大神就是多,她告诉我继承和实现是不一样的,如果普通类没指定父类只实现了接口,那这个类就默认是Object的子类。
好吧,再举个实现接口的例子:
- public class Main {
- public static void main(String[] args) {
- InnerTest inner = new InnerTest();
- Test t = inner.get();
- System.out.println(t.getI());
- }
- }
- interface Test {
- public int getI();
- }
- class InnerTest {
- public Test get() {
- return new Test() {
- // @Override
- public int getI() {
- return 10;
- }
- };
- }
- }
- javap -c InnerTest$$$$$$$$1
复制代码 运行javap -c InnerTest$1的结果
- class InnerTest$$$$1 implements Test {
- final InnerTest this$$$$0;
- InnerTest$$$$1(InnerTest);
- Code:
- 0: aload_0
- 1: aload_1
- 2: putfield #1 // Field this$$$$0:LInnerTest;
- 5: aload_0
- 6: invokespecial #2 // Method java/lang/Object."<init>":
- ()V
- 9: return
- public int getI();
- Code:
- 0: bipush 10
- 2: ireturn
- }
复制代码 6: invokespecial #2 // Method java/lang/Object."<init>" 可以看到确实是调用的Object的构造函数。
所以,就算匿名内部类没有名字,编译器还是会自动为其加上一个名字,然后用它的父类构造函数去将其初始化。
---------------------- <a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net培训</a>、期待与您交流! ----------------------