Java中对象的访问
JAVA是面向对象的语言,那么在JAVA虚拟机中,存在非常多的对象,对象访问是无处不在的。即时是最简单的访问,也会涉及到JAVA栈、JAVA堆、方法区这三个非常重要的内存区域之间的关联关系。
比如:
Object obj = new Object();
其中,“Object obj”这部分语义作为一个reference类型数据出现,将存储到JAVA栈的本地变量表中。new Object()将生成一个实体对象,存储在JAVA堆中,包含了Object类型的所有实例数据值(对象中各个字段的数据)的结构化内存,根据具体类型以及虚拟机实现的对象内存布局的不同,这块内存的长度是不固定的。另外,在JAVA堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现接口、方法等)的地址信息,这些类型数据存储在方法区中。
由于reference类型在JAVA虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用该通过哪种方式去定位,以及访问到JAVA堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:句柄和直接指针。
- 句柄
JAVA堆中将会划分出来一块内存作为句柄池,reference中就是存储了对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。
使用句柄访问的最大好处是reference中存储的是稳定的句柄地址,在对象被移动时,只会改变句柄中的实例数据指针,而reference本身不需要被修改。
- 直接指针
相比较句柄的访问方式,JAVA堆中不会单独划分内存,reference中直接存储了对象地址,而对象中包含了对象类型数据的地址信息。
使用直接指针的最大好处就是速度更快,节省了一次指针定位需要的时间开销,由于JAVA对象访问十分频繁,这类开销积小成多后也是一项非常可观的执行成本。Sun HotSpot虚拟机使用的就是这种访问方式。
一个实体类,名为Stu:
[html] view plain copy
- public class Stu extends Object{
- private String name;
- private int age;
- public Stu(String name,String age){
- this.name = name;
- this.age = age;
- }
- public String getName(){
- return this.name;
- }
- ...
- }
创建Stu对象:
Stu kevin = new Stu(“kevin”,15);
这样根据上文解释如下:
kevin作为一个reference类型的变量存储在本地变量表中,在hot spot虚拟机中,存储的是(kevin=)具体对象的直接地址;new Stu(“kevin”,15)就是实例化了一个对象,JAVA堆中Stu实体类的所有的字段信息,比如name=”kevin”,age=15。此时,JAVA堆中还存储了Stu对象的类型数据的地址信息,通过这个地址在方法区中可以查找对象的类型、父类、实现的接口、方法等信息。