Object.toString()打印“地址”的原理

@(java)

首先,打印的绝不是地址

public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

可以发现我们打印的是调用对象的对应Class对象的getName()方法返回值和hashcode()方法的16进制表示。

Object.hashCode()是什么?

native方法指原生态方法,它调用的不是java语言,而是其他语言,比如C语言。

阅读hashCode的spec,我们发现根本没有提及其实现方式

/ **

*返回对象的哈希码值。这种方法是

*支持哈希表的好处,例如那些提供的哈希表

* {@link java.util.HashMap}。

* {hashCode}的一般合约是:

* 每次在同一个对象中调用多次

*执行Java应用程序,即{hashCode}方法

*必须始终返回相同的整数,不提供任何信息

*用于在对象上进行修改的{@code equals}比较。

*这个整数不需要从一个执行中保持一致

*应用程序到另一个执行相同的应用程序。

* 如果根据equals(Object)}两个对象相等

*方法,然后在每个方法上调用{@code hashCode}方法

*这两个对象必须产生相同的整数结果。

* 如果两个对象不相等,则不需要

*根据{@link java.lang.Object#equals(java.lang.Object)}

*方法,然后在每个方法上调用{@code hashCode}方法

*两个对象必须产生不同的整数结果。但是,那

*程序员应该知道产生不同的整数结果

*用于不相等的对象可以提高散列表的性能。

*尽可能合理实用,由。定义的hashCode方法

* class {@code Object}确实为不同的返回不同的整数

*对象。 (这通常通过转换内部来实现

*对象的地址转换为整数,但是这个实现

*技术不是必需的

* Java™编程语言)。

* @返回此对象的哈希码值。

* @see java.lang.Object#equals(java.lang.Object)

*参见java.lang.System#identityHashCode

* /

再参考最近几个版本jdk的API简介中对hashcode实现的介绍

  • jdk8:This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.(ps:这句话不是很合适,java有垃圾回收机制,其为了整理内存会执行“堆压缩”,将被占用的内存集中在一起减少内存碎片,故内部地址也可能被修改,使用内部地址来生成hashcode不是很好)
  • jdk9/10:The hashCode may or may not be implemented as some function of an object's memory address at some point in time.

从java源码中们不能得知hashcode的具体实现方式,只知道其spec。api描述也非常暧昧。

我们可以推测的是jvm的设计目标包括跨平台适用,所以其hashcode的实现应该是在各个平台上不同的,或者与平台无关。

关于Object.hashCode()原理的stack overflow高票答案

更深入的理解应该是困难的,所以下面我整理了stack overflow的高票答案,仅供参考。请注意它的时效性,虽然我已经选取最新的,但是还是可能有出入,建议作为阅读材料来处理,毕竟hashCode到底如何实现和我们使用java无关。

在HotSpot JVM默认情况下,第一次调用非超载Object.hashCode或System.identityHashCode随机数时会生成并存储在对象头中。随后调用Object.hashCode或System.identityHashCode仅从头>中提取此值。默认情况下,它与对象内容或对象位置没有什么共同之处,只是随机数。此行为由-XX:hashCode=n具有以下可能值的HotSpot JVM选项控制:

  • 0:使用全局随机生成器。这是Java 7中的默认设置。它具有的缺点是,来自多个线程的并发调用可能会导致争用条件,从而导致为不同对象生成相同的hashCode。而且在高度并发环境中,由>于争用(使用来自不同CPU内核的相同内存区域),可能会出现延迟。
  • 1:使用对象指针与一些在“世界停止”事件中更改的随机值混合,因此在停止世界事件(如垃圾收集)生成的hashCode之间是稳定的(用于测试/调试目的)
  • 2:始终使用1(用于测试/调试目的)
  • 3:使用自动增加数字(为了测试/调试目的,还使用全局计数器,因此争用和竞争条件是可能的)
  • 4:如果需要,使用修剪为32位的对象指针(用于测试/调试目的)
  • 5:使用一些没有先前缺点的线程局部xor-shift随机生成器。这是Java 8中的默认设置。

    请注意,即使您设置了-XX:hashCode=4,hashCode也不会始终指向对象地址。对象可能会稍后移动,但hashCode将保持不变。另外,对象地址分布不均匀(如果您的应用程序使用的内存不足,大多数对象将彼此靠近),因此如果使用此选项,最终可能会出现不平衡的哈希表。

    如果hashCode()没有被覆盖,什么是对象的哈希码?

我们从这个回答能发现,7 8两代的默认实现形式都去除了和地址的关联。猜测这样的实现形式能更好的满足跨平台的设计目标。

我们应该如何使用原生hashCode()

核心观点是hashCode只能被用来判断不相同,不能用来判断相同,Objcet.hashCode()并没有因为是Object的hashCode而有任何特殊之处。

理由很直白:无论是以内部地址生成随机数,还是直接使用随机数生成器生成随机数,其长度都被截取为32位,一定存在重复。我们不能认为hashCode相同则就是同一个对象。hashCode应该被用来优化检索,因为如果hashCode不同则一定不是同一对象。

Object.toString()打印“地址”的原理的更多相关文章

  1. JVM源码分析之深入分析Object类finalize()方法的实现原理

      原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 ​“365篇原创计划”第十篇. 今天呢!灯塔君跟大家讲: 深入分析Object类finalize()方法的实现原理 finalize 如果 ...

  2. NAT地址转换原理全攻略

    NAT转换方式及原理 在NAT的应用中,可以仅需要转换内部地址(就是“内部本地址”转换成“内部全局地址”),这是最典型的应用,如内部网络用户通过NAT转换共享上网:也可以是仅需要转换外部地址(就是“外 ...

  3. Redundant Call to Object.ToString()

    Redundant Call to Object.ToString() The + operator for string is overloaded to call String.Concat pa ...

  4. Python动态网页爬虫-----动态网页真实地址破解原理

    参考链接:Python动态网页爬虫-----动态网页真实地址破解原理

  5. day05(Object,tostring(),equals(),System,Date,SimpleDateFormat,拆装箱,正则表达式)

    Object类, 是所应类的父类: 拥有自己的方法:常用的    红颜色标记的为常用的方法 toString() 用法:打印对象的地址值 getClass() 获取当前类的字节码文件getName() ...

  6. javascript系列--Object.assign实现浅拷贝的原理以及实现

    一.前言 之前在前面一篇学习了赋值,浅拷贝和深拷贝.介绍了这三者的相关知识和区别. 传送门:https://www.mwcxs.top/page/592.html 本文会介绍浅拷贝Object.ass ...

  7. 空类生成对象输出的结果是什么? toString()输出 覆写Object toString()方法输出的结果是什么

    空类生成对象输出的结果是什么? 输出的是对象在内存空间地址的哈希值 com.swift.P@1db9742 空类生成对象toString()输出的结果是什么? 输出的是对象在内存空间地址的哈希值的字符 ...

  8. Object toString方法

    1.System.out.println()里的参数会自动调用toString方法. package com.mydemo.controller; // 1.getClass().getName() ...

  9. java nginx等代理或网关转发请求后获取客户端的ip地址,原理

    在没有网关或者反向代理软件情况下,java里获取客户端ip地址的方法是request.getRemoteAddr() 先解释下http协议和TCP协议: 网页默认是进行http连接了,http协议即超 ...

随机推荐

  1. MVC CRUD 的两种方法

    //Index.cshtml @model IQueryable<MvcExam2.Models.Product>@{    Layout = null;}<!DOCTYPE htm ...

  2. VS点击调试卡住的问题解决方案(转载)

    本来今天好好的,不知道弄到了什么,调试不了了,一点击立马卡住,就一直在那转,就在网上找了找解决方案,下面给大家列出来几种可能会卡住的问题已经解决方案 1:加载调试符号引起的卡住 解决方案: 在“选项” ...

  3. 修改Android Studio默认的API Level(SDK版本)

    原文:修改Android Studio默认的API Level(SDK版本) Android Studio(2.1.2)新建工程的时候只会让你选择最低支持的SDK版本,默认的目标编译SDK版本会以系统 ...

  4. 【MVC 笔记】MVC 自定义 Attribute 属性中的猫腻

    原想在 MVC Action 上加一个自定义 Attribute 来做一些控制操作,最先的做法是在自定 Attribute 中定义一个属性来做逻辑判断,可惜事与愿违,这个属性值居然会被缓存起来,于是于 ...

  5. Qt 下快速读写Excel指南(尘中远)

    Qt Windows 下快速读写Excel指南 很多人搜如何读写excel都会看到用QAxObject来进行操作,很多人试了之后都会发现一个问题,就是慢,非常缓慢!因此很多人得出结论是QAxObjec ...

  6. 冒泡排序C#实现,使用委托,包括三种方式:Fun<>,匿名方法,Lambda表达式

    冒泡排序是一种简单的排序方法,适合于小量数字排序,对于大量数字(超过10个),还有更高效的排序方法. 这里的实现的冒泡排序,需实现功能: 不仅数字排序,还要对任意对象排序 示例: 对People对象的 ...

  7. Tcptrack —— TCP 连接的嗅探器

    分享 <关于我> 分享  [中文纪录片]互联网时代                 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...

  8. 用C实现OOP面向对象编程(1)

    如摘要所说,C语言不支持OOP(面向对象的编程).并这不意味着我们就不能对C进行面向对象的开发,只是过程要复杂许多.原来以C++的许多工作,在C语言中需我们手动去完成. 博主将与大家一起研究一下如下用 ...

  9. FireMonkey下的异形窗体拖动(需要使用FmxHandleToHwnd函数转化一下句柄)

    DelphiXE2 Firemoney FMX 的窗体不只是为windows的, 所以很多功能都没有了. 最常见的就是拖拽了 先看 VCL时代 一个经典拖动代码 ReleaseCapture(); S ...

  10. uni-app中Vuex的引用

    //store 中 store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vue ...