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.动态分派(重写)是要在运行期才确定的。