class A {
private void a() {
System.out.println("A.a");
} private void b() {
System.out.println("A.b");
} public void ab() {
System.out.println(this.getClass());
this.a();
this.b();
}
}public class B extends A {

public void a() {
System.out.println("B.a");
} public void b() {
System.out.println("B.b");
} public static void main(String[] args) {
new B().ab();
}
}输出结果是:
class cn.icast.javaenhance.extend.B
A.a
A.b这我就步理解了,为什么this.class是B,那么this就表示对象B,那么为什么this.a(),和this.b()
输出的都是A类的方法呢?

解决方案 »

  1.   

    因为你的ab()方法在B里面没有,所以就回到父类A,而A里面的this就是A
      

  2.   

    我现在在ab()方法里头调用,a()和b()这两个方法A类和B类都是有的,我现在的问题是this.a()为什么和this.b()为什么步调用B类的a()和b(),因为this.class是B.class,那么this就是B类的实例对象,那么就应该调用B类的a()和b()方法,可是结果确不是这样
      

  3.   

    实在弄不清楚的话,debug一下
      

  4.   

    private方法是不会被override的,也就是说A.a()和B.a()其实没关系。你可以尝试修改父类的方法private<->public修饰符,并在子类方法添加@Override,可以发现,父类private时,子类方法@Override报错
      

  5.   

    如果父类中的方法被子类override 调用的就是子类中的a() b(),private 的方法无法被override 而且父类对子类的public a(), public b() 是不知道的, 明显是在调用父类中的 a(), b()
      

  6.   

    class A {
    public void a() {
    System.out.println("A.a");
    } public void b() {
    System.out.println("A.b");
    } public void ab() {
    System.out.println(this.getClass());
    this.a();
    this.b();
    }
    }public class B extends A { public void a() {
    System.out.println("B.a");
    } public void b() {
    System.out.println("B.b");
    }

    public static void main(String[] args) {
    new B().ab();
    }
    }结果:
    class cn.com.ylchen.demo.java.B
    B.a
    B.b
      

  7.   

    很简单的道理啊。this.getClass()方法返回的是你运行时this的类型。这个方法是继承于Object。new B()这个对象运行时是B,没有问题。但是this.a()为啥返回的是A.a?因为子类没有重写ab()方法,并且父类的a()方法是private修饰的。这样子类对象只能调用父类的ab方法。同时,a方法是private的,这就意味着不可能被子类重写,这样父类就无法知道子类是否有a方法了。于是,只能调用父类的private方法。如果你把private换成public,就会输出B.a了。
      

  8.   


    错错错,全错,大错特错!!!!!java编程思想说,当调用一个类的方法时,会将当前引用偷偷传给调用的方法,调用ab()方法实际等于new B().ab(引用); 而在ab方法中相当于ab(this);结果可想而知,this.getClass() 根本就是 “B”对象。
      

  9.   

    我觉的大家都没有说到LZ想要的东西上,我现在重新阐明一下楼主的问题:首先,关于Java方法调用的动态和静态绑定机制我默认大家都知道了。根据Java方法调用的动态绑定机制(运行时绑定)。我们可以知道main方法中,new B().ab(); 实际过成应该是 ab(new B());这里的new B()是隐式参数,也就是我们常说的this.所以在A类中定义的ab()方法 打印this.getClass()确实是我们想要的class cn.icast.javaenhance.extend.B这一点是毫无疑问的,大家都清楚。但是LZ的问题是,既然在运行时this的实际类型是B类,为什么在调用this.a()方法的时候显示的是A.a()而不是B.a()。根据动态绑定原则,应该调用的是this实际类型B中的a()方法呀?我将A类反编译了一下:我很惊讶的发现A类ab()方法的指令是这样的:
      public void ab();
        0  aload_0 [this]
        1  invokevirtual testa.A.a() : void [30]//这里调用的invokevirtual 指令居然查找的是A类中的a()方法。
        4  return
          Line numbers:
            [pc: 0, line: 10]
            [pc: 4, line: 11]
          Local variable table:
            [pc: 0, pc: 5] local: this index: 0 type: testa.A
    }
    大家可以去试试,确实有些纳闷。我原来自认为对Java的方法调用十分了解,现在看来还不是很清楚的。期待牛人的牛解???
      

  10.   

    java继承机制与权限机制还是他妈有玄机的
      

  11.   

    我查看了《thinking in java 中文第四版》P151,《Core Java 中文第7版》P148-P151,感觉都没有说清楚。我还看了《深入JVM 中文第二版》P329页。我有这么一个感觉:
    我们都知道,当类中的方法是static或final的时候,调用后class文件字节码指令用的是invokespecial。
    这是因为static方法不属于对象,final方法无法覆盖,所以都不存在多态的问题。而所有的调用普通方法的指令都是invokevirtual,我觉得这个指令是专门用于处理多态问题的。
    也就是说16楼中我对A类中ab()方法反编译出的invokevirtual testa.A.a(),虽然表面上查找的是A的a(),但应该存在一个多态问题,也就是说this实际类型是B的,invokevirtual 指令会考虑到this实际类型转而去调用B的a()方法。这个只是我的一个猜测。如果是真的是这样的话,那么invokevirtual指令的执行流程应该是这样的:
    (1) 首先invokevirtual指令是A类中的ab()方法内的调用指令,所以invokevirtual指令会查找A类中的a()方法。
    (2) 如果A类中的a()方法是private的,这说明此时的A中a()方法相当于final,子类无法覆盖。所以也就不去找别的可能的覆盖方法了。这时即使调用invokevirtual方法指令的实际对象this是B类型,也不管了。
    (3) 如果A类中的a()方法是public的,也就是说此时的a()方法完全有可能被子类的a()覆盖,此时invokevirtual指令就会去找实际类型B中的a()方法了。我觉得应该是这个样子的。所以关键是invokevirtual指令的解释问题。
      

  12.   

    public final native Class<? extends Object> getClass();
      

  13.   

    楼主的A.java经 javap 反汇编后的结果是:
    Compiled from "A.java"
    class test.A extends java.lang.Object{
    test.A();
      Code:
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: returnprivate void a();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #3; //String A.a
       5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: returnprivate void b();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #5; //String A.b
       5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: returnpublic void ab();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokevirtual #6; //Method java/lang/Object.getClass:()Ljava/lang/Class;
       7: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       10: aload_0
       11: invokespecial #8; //Method a:()V
       14: aload_0
       15: invokespecial #9; //Method b:()V
       18: return}
    注意a()与b()均为私有方法。所以我们看到ab()方法中的汇编代码是
       10: aload_0
       11: invokespecial #8; //Method a:()V
       14: aload_0
       15: invokespecial #9; //Method b:()V由于invokespecial指令的原因,ab()方法调用的是“invokespecial  #1;”指定的A类中的方法,A类构造方法的汇编如下
    test.A();
      Code:
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: return-----------------------------------------
    如果我们将A.java中的a()与b()写成公有方法,如下:class A {    public void a() {        System.out.println("A.a");
        }    public void b() {        System.out.println("A.b");
        }    public void ab() {        System.out.println(this.getClass());
            this.a();
            this.b();
        }
    }
    利用javap反汇编得到的结果是Compiled from "A.java"
    class test.A extends java.lang.Object{
    test.A();
      Code:
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: returnpublic void a();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #3; //String A.a
       5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: returnpublic void b();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #5; //String A.b
       5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: returnpublic void ab();
      Code:
       0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokevirtual #6; //Method java/lang/Object.getClass:()Ljava/lang/Class;
       7: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       10: aload_0
       11: invokevirtual #8; //Method a:()V
       14: aload_0
       15: invokevirtual #9; //Method b:()V
       18: return}
    我们看到ab()方法中的汇编代码是
       10: aload_0
       11: invokevirtual #8; //Method a:()V
       14: aload_0
       15: invokevirtual #9; //Method b:()V由于用到的是invokeviertual指令,所以会调用到子类中同名的方法,也就是我们所说的继承方法。
      

  14.   


    这里的问题不是this所导致的,而是private与public的不同所导致的。
      

  15.   

    还有一点要搞清楚:这是LZ在A中的ab()方法
    public void ab() {
       System.out.println(this.getClass());
       this.a();
       this.b();
    } 在编译后、运行前的.class中。 
    (1) System.out.println(this.getClass()); 
    被编译成: invokevirtual java.io.PrintStream.println(java.lang.Object) : void [34]
    (2) this.a();
    被编译成: invokespecial testa.A.a() : void [37]可以这样解释:在运行之前,编译器是不可能知道this指的是哪一个对象的(编译器不是JVM)。
    因此this.a();被编译成invokespecial testa.A.a()。这并不表示会调用testa.A.a()方法。因为invokespecial指令是具有多态功能的,换句话说这条指令会根据运行时this的实际对象来动态绑定a()方法。所以运行时,我们看到了System.out.println(this.getClass()); 的结果是B类,因此JVM知道invokespecial需要执行动态绑定机制了。但可惜的是A中的a()方法是private的,也就是无法被子类覆盖。因此什么都免了,JVM直接就执行编译器编译的指令了invokespecial testa.A.a()。
      

  16.   

    关键就是父类A的a跟b方法都是private,的,所以父类A的ab方法调用的一定是A的a跟b方法,不会是子类的,除非把a跟b方法改成public咯那就会调用重载的方法
      

  17.   

    我感觉  heartraid86  你说的实在是太好了,你对问题的研究程度另我敬佩,我真的很感谢你为我解答这个问题,看来我得深入的了解java的指令集和jvm的工作原理,由于刚毕业忙着找工作,所以不得不给自己灌输很多框架的知识,其实很多基本的东西还是没有理解透彻的!谢谢你! 
      

  18.   

    A.a()与B.a()是两个不同的方法,因此this没有动态绑定B.a()方法,在调用this.a的时候this是A类的引用,他不知道B类有什么方法,所以就调用了A.a();
      

  19.   

    你可以修改父类的private->public试一下
      

  20.   

    学习了,顺便说下自己总结上述牛人的看法调用new B().ab()换个写法就是object.ab(new B());this指针所指向的是new B()。所以this.class 就是B.class。调用this.a(),this.b()。其实是编译器在编译期间就确定下来的。当编译器在首次编译this.a()时候,去查看该函数的定义,发现是private,private无法向下继承,所以就编译成为 invokespecial testa.A.a()。此时和this就一点关系都没啦,已经确定执行的是A.a();Over~我可能说的有问题,欢迎大家指出
      

  21.   

    因为你父类A中的2个方法都是private的,不会被子类继承,所以也就无法构成方法覆盖
      

  22.   

    父类的this是相对父类而言的 因为你类已经实例化 实例化中的this当然是指该类了 
      

  23.   

    你在ab()里调用的this
    指的就是ab方法那个类。并不是你的当前类。
      

  24.   

    http://blog.csdn.net/ZangXT/archive/2009/09/24/4587985.aspx
    随便看看吧,说不定有用呢
      

  25.   

    见多了,就很正常了。把Thinking in java 看了还是挺有用的。
      

  26.   

    this的运用之和它所在的方法中的类有关,在初始化时只在A类中进行,所以this所代表的就是A类了。
      

  27.   

    感觉还是静态动态绑定的问题如果方法是 STATIA FINAL PRIVATE编译器就可以确定调用那个方法。这是静态绑定。
      

  28.   

    所有的楼上的种种说法,
    错误的说法真是多,理解错误还自我圆说
    楼主的问题问得很好,是一个很基本的问题。
    为了更能暴露楼上种种错误说法:可将A中方法a()的private去掉,同时将类B放到与A不同的另一个包中。
    这时再考虑楼主的问题就更能暴露楼上种种错误说法了。1)这样就会生成invokevirtual指令了。因此楼主的问题更主要与invokevirtual指令相关了。
    认真看一下JVM规范中对invokevirtual指令的说明,比所有的那些想当然的解释权威且清楚多了。真是盲人摸象式的各种自我解释。
      

  29.   

    即使方法a()去掉private,只加上final,this.a()调用时仍是invokevirtual指令。
      

  30.   


    我对JVM没有系统学习过,我说的只是一种猜测,觉得应该和invokevirtual有关,但我并不了解这个指令。我的解释应该是不正确的。我还是回去看完JVM再说吧。