java 重载和多态的区别

虚拟函数表是在编译期就建立了,各个虚拟函数这时被组织成了一个虚拟函数的入口地址的数组.而对象的隐藏成员
--虚拟函数表指针是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键。

 http://m.blog.csdn.net/blog/seekcreation/40116455

虚函数表

成员方法的解析

java中方法分派指令:

invokespecial

invokevirtual

invokedynamic

involveinterface

 

 

静态类型,静态分派

实际类型,动态分派

 

 

成员数据解析

根据 java7虚拟机规范 , 成员数据解析过程描述如下:

为了将一个还没有解析的符号引用D解析成一个类(或者接口)C的一个成员,符号引用C必须被先解析。因此任何因在C被解析成类(或者接口)时失败导致抛出的异常都可以被解析符号引用D时抛出。如果C可以被解析成一个类(或者接口),则因D被解析成一个成员引用失败抛出的异常才可以被抛出。

  1. 如果C声明了和D符号引用(名称和描述符)一样的成员引用,则解析成功;
  2. 否则,解析过程递归到类C的直接实现(或者接口C直接继承)的接口中;
  3. 否则,如果C有父类S,则解析过程递归到S中;
  4. 否则,解析失败。

纵使上面解析成功,接着还会验证访问权限:

  1. 如果上面的解析过程解析失败,则直接抛出 NoSuchFieldError;
  2. 否则,如果没有对D没有 获取权限 ,则直接抛出 IllegalAccessError;
  3. 。。。

 

从上面的解析过程可以看到,对于成员数据的访问,虽然成员数据也和方法声明一样有访问限制,但Java并没有用不同的虚拟机指令来区分对不同访问限制的成员数据的访问,而是符号解析后统一进行访问权限的验证检查,而且还可以看出java语言中子类型中声明的成员数据可以覆盖父类型中声明的成员数据的语法在符号解析的规则中就可以实现。下面举例说明四条成员数据访问相关的指令。 

package com.baidu.test;

public class T {
    private int data = 100;
    public static void main(String[] args) {
        T t = new T();
        System.out.println(t.data);
    }
}

部分常量池数据:

 

构造函数中对data赋值:( putfield)

main函数中读取data值:(getfield)

 

package com.baidu.test;

public class T {
    static class A {
        static int data = 1000;
    }

    static class B extends A {

    }

    public static void main(String[] args) {
        System.out.println(B.data);
    }
}

 部分常量池数据:

类A的静态构造初始化块中给data赋值(putstatic)

main方法中读取data的值(getstatic)

稍微留意下可以发现,虽然data是声明在父类A中,但是在T中使用A的子类B访问data时,常量池中依然是描述为对B的成员data访问(见 T的常量池 #22)

posted on 2015-08-14 09:27  寸草之心  阅读(1767)  评论(0编辑  收藏  举报

导航