java中的句柄分为两种:
- 对象句柄
- jvm中对象访问句柄
一、对象句柄
句柄:一个唯一的整数,作为对象的身份id,区分不同的对象,和同类中的不同实例。程序可以通过句柄访问对象的部分信息。句柄不代表对象的内存地址。在Java中的任何东西都可以看做对象,存在一种标识符实际指向一个对象的句柄.在Java的其他地方或者数据中也有称为 "引用"或者 "指针". 只是一个引用地址,我们不能认为Java中没有指针,其实这就是一个指针,我们每次操作对象就是根据句柄去找到对象操作对象的. 即使没有对象,我们也可以让句柄单独存在。
可以将句柄简单的理解为对象的引用.
举一个例子:
Vehicle ve = new Vehicle();
通常把这条语句的动作称之为创建一个对象,其实,它包含了四个动作。
- 右边的“new Vehicle”,是以Vehicle类为模板,在堆空间里创建一个Vehicle类对象(也简称为Vehicle对象)。
- 末尾的()意味着,在对象创建后,立即调用Vehicle类的构造函数,对刚生成的对象进行初始化。构造函数是肯定有的。如果你没写,Java会给你补上一个默认的构造函数。
- 左边的“Vehicle veh 1”创建了一个Vehicle类引用变量。所谓Vehicle类引用,就是以后可以用来指向Vehicle对象的对象引用。
- "="操作符使对象引用指向刚创建的那个Vehicle对象。
我们可以把这条语句拆成两部分:
Vehicle ve;
ve = new Vehicle();
效果是一样的。这样写,就比较清楚了,有两个实体:一是对象引用变量,一是对象本身。
一个Vehicle类可以据此创建出无数个对象,这些对象不可能全叫“Vehicle”。对象连名都没有,没法直接访问它。我们只能通过对象引用来间接访问对象。Java中就是用句柄来标识每一个对象的.
如何更好的理解句柄呢?我们再举一个例子:
Person person;
person = new Person("张三");
person = new Person("李四");
刚开始我们分配了一个句柄,它没有连接到任何对象,它就是null。在第二行,我们new了一个叫“张三”的person,将person指向“张三”这个对象,然后又指向了“李四”这个对象。也就是说,Person person,这句话只是声明了一个Person类的引用,它可以指向任何Person类的实例。
二、对象访问句柄
由于reference类型在Java虚拟机规范里只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。
使用句柄访问方式
如果使用句柄访问方式,Java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。使用句柄方式最大的好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改。
三、使用直接指针访问方式
如果使用该方式,Java堆对象的布局就必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址。使用直接指针方式最大的好处就是速度更快,他节省了一次指针定位的时间开销。
就HotSpot而言,他使用的是直接指针访问方式进行对象访问,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见。
总结,在对象分配的时候,句柄使用较多.在对象访问的时候,其实是可以权衡的,如果使用直接指针的方式进行对象访问,那么更多的就是关注堆中已分配对象的快速访问;如果使用句柄访问的方式,更多的是考虑到GC的时候,对象的移动十分频繁(具体参照JVM垃圾回收算法),那么句柄访问方式会更有优势。所以目前来看,就HotSpot来说,对象分配更多使用句柄,对象访问使用直接指针。
往期精彩内容:
Java知识体系总结(2021版)
Java多线程基础知识总结(绝对经典)
超详细的springBoot学习笔记
常见数据结构与算法整理总结
Java设计模式:23种设计模式全面解析(超级详细)
Java面试题总结(附答案)
原创不易,转载自:https://juejin.im/post/5c849ee16fb9a049f81a1b2e