首页 > 编程语言 > 详细

Scala核心编程_第08章 面向对象编程(中级补充)--java动态绑定与静态绑定

时间:2020-06-01 11:03:47      阅读:38      评论:0      收藏:0      [点我收藏+]

Java方法调用过程中,Jvm是如何知道调用的是哪个类的方法?Jvm又是如何处理?

 

简介

当子类和父类(接口和实现类)存在同一个方法时,子类重写父类(接口)方法时,程序在运行时调用的方法时,是调用父类(接口)的方法呢?还是调用子类的方法呢?我们将确定这种调用何种方法的操作称之为绑定。

绑定又分为静态绑定和动态绑定。在了解动态绑定之前,我们要了解一下JAVA对象模型才能更好的理解java的绑定机制。

1 JAVA对象模型

JAVA虚拟机规范并没有规定JAVA对象在堆里是如何表示的。对象的内部表示也影响着整个堆以及垃圾收集器的设计,它由虚拟机的实现者决定。

JAVA对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有一个对象引用,虚拟机就必须能够快速地定位对象实例的数据。

另外,它也必须能通过该对象引用访问相应的类数据(存储于方法区的类型信息),因此在对象中通常会有一个指向方法区的指针。

当程序在运行时需要转换某个对象引用为另外一种类型时,虚拟机必须要检查这种转换是否被允许,被转换的对象是否的确是被引用的对象或者它的超类型。

当程序在执行instanceof操作时,虚拟机也进行了同样的检查。所以虚拟机都需要查看被引用的对象的类数据。

不管虚拟机的实现使用什么样的对象表示法,很可能每个对象都有一个方法表因为方法表加快了调用实例方法时的效率。

但是JAVA虚拟机规范并未要求必须使用方法表,所以并不是所有实现中都会使用它。

下面是一种JAVA对象的内存表示:

技术分享图片

 

方法数据存放在类的方法区中,包含一个方法的具体实现的字节码二进制。方法指针直接指向这个方法在内存中的起始位置,通过方法指针就可以找到这个方法。

方法表是一个指向方法区中的方法指针的数组。方法表中不包含static、private等静态绑定的方法,仅仅包含那些需要动态绑定的实例方法。

在方法表中,来自超类的方法出现在来自子类的方法之前,并且排列方法指针的顺序和方法在class文件中出现的顺序相同,这种排列顺序的例外情况是,被子类的方法覆盖的方法出现在超类中该方法第一次出现的地方。

2.静态绑定

静态绑定是在程序执行前就已经被绑定了(也就是在程序编译过程中就已经知道这个方法是哪个类中的方法)。

在Java中,final、private、static修饰的方法以及构造函数都是静态绑定的,不需程序运行,不需具体的实例对象就可以知道这个方法的具体内容。

public class StaticBindDemo {

    public static void s1() {
        System.out.println("static s1");
    }

    private void p1() {
        System.out.println("private p1");
    }

    public final void f1() {
        System.out.println("final f1");
    }
}
class StaticCall {
    public static void main(String[] args) {
        StaticBindDemo sbd = new StaticBindDemo();
        StaticBindDemo.s1();
        sbd.f1();
    }
}

技术分享图片

 

 上面的源代码反编译后,我们可以看到

调用的是静态方法
8: invokestatic  #4                  // Method StaticBindDemo.s1:()V
  1. #4指的是常量沲中的第4个常量表索引项,记录的是方法s1的符号引用,jvm会根据这个符号引用找到方法f1,所在的类的全限定名:StaticBindDemo
  2. 紧接着JVM会加载、边接和初始化类StaticBindDemo类
  3. 然后在StaticBindDem类所在的方法区中找到s1()方法的直接地址,并将这个直接地址记录到StaticCall类的常量池索引为4的常量表中。这个过程叫常量池解析 ,以后再次调用StaticBindDemo.s1时,将直接找到s1方法的字节码;
  4. 完成了StaticCall类常量池索引项4的常量表的解析之后,JVM就可以调用s1()方法,并开始解释执行f1()方法中的指令了。
通过上面的过程,我们发现经过常量池解析之后,JVM就能够确定要调用的s1()方法具体在内存的什么位置上了。实际上,这个信息在编译阶段就已经在StaticCall类的常量池中记录了下来。
这种在编译阶段就能够确定调用哪个方法的方式,我们叫做静态绑定机制
 
注:Java中只有private、static和final修饰的方法以及构造方法是静态绑定。
  1. private方法的特点是不能被继承,也就是不存在调用其子类的对象,只能调用对象自身,因此private方法和定义该方法的类绑定在一起。
  2. static方法又称类方法,类方法属于类文件。它不依赖对象而存在,在调用的时候就已经知道是哪个类的,所以是类方法是属于静态绑定。
  3. final方法:final方法可以被继承,但是不能被重写,所以也就是说final方法是属于静态绑定的,因为调用的方法是一样的。
总结:如果一个方法不可被继承或者继承后不可被覆盖,那么这个方法就采用的静态绑定。

Scala核心编程_第08章 面向对象编程(中级补充)--java动态绑定与静态绑定

原文:https://www.cnblogs.com/wqbin/p/13023692.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!