JAVA方法分派笔记

有两个让我不太明白的调用:

1.http://smiky.iteye.com/admin/blogs/996590

2. 

 

package org.gerry;

public class Son extends Parent
{
	public void test()
	{
		super.test();
		System.out.println( this );
		this.duo();
	}
	public void duo()
	{
		System.out.println("Son duo");
	}
}

 

 

package org.gerry;

public class Parent
{
	public void test()
	{
		System.out.println("Parent test...");
		System.out.println( this );
		this.duo();
	}
	
	public void duo()
	{
		System.out.println("Parent duo");
	}
	
}

 

 

 

package org.gerry;

public class client
{
	public static void main(String[] args)
	{
		new Son().test();
	}
}
 

 

 

第二个的结果相信会有人跟我一样弄错,父类的test()方法内会调用那个方法?子类or父类的?

字节码先上:
parent的test方法
 public void test();
   flags: ACC_PUBLIC
   Code:
     stack=2, locals=1, args_size=1
        0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
        3: ldc           #21                 // String Parent test...
        5: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        8: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
       11: aload_0
       12: invokevirtual #29                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       15: aload_0
       16: invokevirtual #32                 // Method duo:()V
       19: return
     LineNumberTable:
       line 7: 0
       line 8: 8
       line 9: 15
       line 10: 19
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
              0      20     0  this   Lorg/gerry/Parent;
 可以看出偏移量为16的指令为invokevirtual,说明这个方法是个多态调用,但是看下面的变量表,很显示这个this是Parent类型的,根据方法解析规则:(下面是常量表中的类方法表
#32 = Methodref          #1.#33         //  org/gerry/Parent.duo:()V)
方法的符号引用在指令调用之前替换成直接引用,先找到#1对应的Parent(不用说Parent早就换成了Parent.class对应的直接引用),即然有了Class对象,接着就是在该类中查找#33对应的NameAndType类型常量池的索引,说白了就是在类中找duo方法,找得到的话就换成方法的直接引用
照上面的分析,结果应该是调用父类的duo()才对,可为什么调用的是子类的duo呢?可能有人说,invokevirtual表示调用多态方法啊,但是我父类中有duo方法啊,就算多态也应该找我自己的啊,轮不到子类啊
出现这种情况,只能在这种情况才可能,就是Parent的本地变量表中的this的直接引用就是指向 main方法中new的那个Son,在这种情况下多态才能体现出来(只有 invokevirtual对应的操作数this是Son,它才会动态分派到Son的duo方法)

从下面的打印结果能看出这点:Son中的this与Parent中的this指向的是同一个地址
Parent test...
org.gerry.Son@2f995c9a
Son duo
org.gerry.Son@2f995c9a
Son duo
 
还有一点顺带提一下,不知道对不对,
super根本就屁用没有,只不过指定编译器执行父类的方法,下面是Son的test()的字节码:
public void test();
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=1, args_size=1
       0: aload_0
       1: invokespecial #15                 // Method org/gerry/Parent.test:()V
       4: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       7: aload_0
       8: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      11: aload_0
      12: invokevirtual #29                 // Method duo:()V
      15: return
    LineNumberTable:
      line 7: 0
      line 8: 4
      line 9: 11
      line 10: 15
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      16     0  this   Lorg/gerry/Son;
 从偏移为1的指令看出,它就是调用父类的test方法,而方法在执行的时候会传一个隐藏的this作为参数(从实际方法的本地方法表中可以看出),是不是这里是将Son的对象传到了Parent的test方法作为隐藏的this?估计也只有这个可能,
那么有什么方式可以获取到父类的对象呢?子类初始化时会初始化父类,那么生成的父类对象去那啦?可以调用到吗?如果调用不到的话在这种情况下算生成了几个对象?


对于上面第一个是不是也可以这样理解,对于属性只管其静态类型(本地变量表中的类型)?父类中的this的类型是父类本身,所以改奕的是父类的值,对子类无影响?
看来我是JS写多了,以为this是谁改变的就是谁的字段的值,走火入魔了

看来我的猜测是对的,将父类中的this强制改成子类,那么父类方法中操作的就是子类的属性了,看来对属性的操作只看静态类型
class A extends E{  
    int x;  
    int y;  
    public void setValue(int i,int j){  
        this.x = i;  
        this.y = j;  
//        B b = (B)this;
//        b.x = i;  
//        b.y = j;  
    }  
    
    public int compute(){  
        return this.x * this.y;  
    }  
      
}  
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值