Java方法(虚拟机角度)原理分析

Java方法

一.概述:

       1.方法里面的代码是储存在内存中的,按微机知识就是储存在代码段(DS)里。

       2.方法是属于对象的,对象是类的实例。所以当一个类被加载时,它的类信息会被储存在方法区里,这里的类信息包括              在类里定义的方法的符号引用,符号引用不是真正方法在内存区的调用入口,要从符号引用得到方法的直接引用才能调    用到方法。而在编译期类信息也只能加载到方法的符号引用(这一点与传统编译原理不一样),而从符号引用得到方法              的直接引用需要到运行期才能确定,这一点给了Java方法调用很强的动态扩展能力,比如方法的重写。

 

二.栈帧:

       1.Java虚拟机栈是一种栈数据结构,而栈帧就是虚拟机栈的元素。一个方法的调用到return结束相当于栈帧入栈到出栈              的过程。每个栈帧储存了方法的局部变量表,操作数栈,动态链接,方法返回地址,额外附加信息。在实际开发中,动    态链接,方法返回地址,额外附加信息称为栈帧信息。

       2.一个栈帧需要多大的局部变量表,多深的操作数栈,多大的内存是在代码编译的时候就确定了,不会受运行期影响。

      

       3.局部变量表:

              1.用于存放方法参数,方法内部定义的局部变量。

              2.局部变量表的容量以变量槽(slot)为最小单位,Java虚拟机规定一个slot要可以存放一个32位以内的数据类型                     (当然slot也可以是64位的)。Java 32位以内的数据类型有boolean,byte,char,short,int,float,reference,returnaddress。             这就是为什么只有1位的boolean,只有8位的byte等也是使用32位来储存的原因。(而android的则是slot最小为               8位,用来保证boolean和byte的储存)

              3.对于reference类型,它是用来指向对象实例的。Java虚拟机规定它至少做到两点。第一,该引用能直接或间接地              查找到在Java对中该对象数据储存的起始地址。第二,该引用直接或间接等查找到该对象所属类在方法区中储存的           类信息,这个的作用在放射中就会用到。

              4.对于64位数据类型,虚拟机使用两个slot来存放数据。Java虚拟机规定的明确64位数据的有long和double。

              5.对于非静态方法,局部变量表的第一个slot存放的是该方法所属对象的引用,即平时使用的this。

              6.为了节省栈帧空间,slot是可复用的。当是这会带来副作用,如影响GC行为。slot复用就是,当方法在执行时,              如果当前程序计数器位置之前的变量已经不用了,则可以把其slot空间用来存放新的变量。说这会影响GC的原因                     是,如果有一个slot指向的对象已经不用了,按理GC会把它回收掉,都是因为slot复用的原因,该slot没有别删                     除,而是用来储存后面的变量,如果这时候在该slot还没重新储存新变量时程序正在执行耗时的操作,那么该slot               指向的还是之前已经失效的对象,根据垃圾回收机制,这个对象还是不会被GC回收的。解决该问题的方法是对无                     用的变量,手动置null。

              7.虚拟机没有为局部变量赋系统零值,所以在没有手动为局部变量赋初始值时是不可以所以的。这一点和类变量不                     同。

      

       4.操作数栈:

              1.栈深度在编译期已确定。

              2.操作数栈和微机的堆栈段SS原理差不多,即通过进栈和出栈来操作方法的临时数据。

 

       5.动态链接:

              1.每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用(类信息中),持有该引用是为了支持方法调用过           程中的动态链接。

              2.动态链接主要用于方法的重载和重写。

 

       6.方法返回地址:

              1.方法的退出有两种情况,第一是执行引擎遇到方法返回指令。第二种是方法在执行过程中遇到异常,并且该异常                     没有在方法内部得到处理。

              2.无论哪种方法退出,都需要回到方法被调用的位置。

              3.方法退出相当于把当前栈帧出栈,这时可能执行的操作有,恢复上层方法的局部变量表,操作数栈,把返回值压                     到调用者的操作数栈,调整PC计数器的值指向方法调用指令后面的一条指令。

       7.附加信息:

              1.附加信息可以是调试相关信息。

 

      

三.方法的调用(应该说是方法的确定)

       方法的调用不是方法的执行,不涉及方法的运行。方法的调用在作用是用来确定要具体在执行时使用哪个方法,比如方法的重写,其方法的调用是用来确定具体要执行哪个重写的方法。

       方法的调用可

       1.方法的解析:

              1.所有方法调用中的目标都在class文件里,也就是类储存在方法区里的类信息里面的符号引用。在类的解析阶段会           把一部分的符号引用转化为直接引用。而能在这时候转化为直接引用的方法是那些可以在程序运行前,即编译期就           可确定的方法版本,这就叫方法的解析。可以在编译期确定的方法有静态方法,私有方法,final方法,因为这两种              方法都不能通过重写和重载类修改。

              2.方法的解析属于静态的。

       2.方法的分派:

              A a = new B( ),这里A是静态类型,B是实际类型。静态类型是编译时就确定了的,实际类型要在运行时才确定。       强制类型转换改变的是变量的静态类型。

              1.静态(多)分派

                     1.方法的静态分派对应的有方法的重载。

                     2.在调用重载方法时,选择的是形参的静态类型与方法定义参数的类型最接近的方法。

                     3.静态分派(重载)在编译期已经确定。

              2.动态(单)分派

                     1.方法的动态分派对应的有方法的重写。

                     2在调用重写方法时,选择的是与变量的实际类型最近的方法。

                     3.动态分派(重写)是要在运行期才确定的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值