但是通过这种比较的方式效率很低,时间复杂度比较高 。那么我们是否可以通过某种编码方式,将每一个对象都具有某个特定的码值,根据码值将对象分组然后划分到不同的区域,这样当我们需要在集合中查询某个对象时,我们先根据该对象的码值就能确定该对象存储在哪一个区域,然后再到该区域中通过equals方式比较内容是否相等,就能知道该对象是否存在集合中 。
通过这种方式我们减少了查询比较的次数,优化了查询的效率同时也就减少了查询的时间 。
这种编码方式在 Java 中就是 hashCode 方法,Object 类中默认定义了该方法,它是一个 native 修饰的本地方法,返回值是一个 int 类型 。
/** * Returns a hash code value for the object. This method is * supported for the benefit of hash tables such as those provided by * {@link java.util.HashMap}. * ... * As much as is reasonably practical, the hashCode method defined by * class {@code Object} does return distinct integers for distinct * objects. (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.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */public native int hashCode();复制代码从注释的描述可以知道,hashCode 方法返回该对象的哈希码值 。它可以为像 HashMap 这样的哈希表有益 。Object 类中定义的 hashCode 方法为不同的对象返回不同的整形值 。具有迷惑异议的地方就是This is typically implemented by converting the internal address of the object into an integer这一句,意为通常情况下实现的方式是将对象的内部地址转换为整形值 。
如果你不深究就会认为它返回的就是对象的内存地址,我们可以继续看看它的实现,但是因为这里是 native 方法所以我们没办法直接在这里看到内部是如何实现的 。native 方法本身非 java 实现,如果想要看源码,只有下载完整的 jdk 源码,Oracle 的 JDK 是看不到的,OpenJDK 或其他开源 JRE 是可以找到对应的 C/C++ 代码 。我们在 OpenJDK 中找到 Object.c 文件,可以看到hashCode 方法指向 JVM_IHashCode 方法来处理 。
static JNINativeMethod methods[] = { {"hashCode", "()I", (void *)&JVM_IHashCode}, {"wait", "(J)V", (void *)&JVM_MonitorWait}, {"notify", "()V", (void *)&JVM_MonitorNotify}, {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},};复制代码而JVM_IHashCode方法实现在 jvm.cpp中的定义为:
JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))JVMWrApper("JVM_IHashCode");// as implemented in the classic virtual machine; return 0 if object is NULLreturn handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ; JVM_END 复制代码这里是一个三目表达式,真正计算获得 hashCode 值的是ObjectSynchronizer::FastHashCode,它具体的实现在synchronizer.cpp中,截取部分关键代码片段 。
intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) { if (UseBiasedLocking) {......// Inflate the monitor to set hash code monitor = ObjectSynchronizer::inflate(Self, obj); // Load displaced header and check it has hash code mark = monitor->header(); assert (mark->is_neutral(), "invariant") ; hash = mark->hash(); if (hash == 0) { hash = get_next_hash(Self, obj); temp = mark->copy_set_hash(hash); // merge hash code into header assert (temp->is_neutral(), "invariant") ; test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark); if (test != mark) { // The only update to the header in the monitor (outside GC) // is install the hash code. If someone add new usage of // displaced header, please update this code hash = test->hash(); assert (test->is_neutral(), "invariant") ; assert (hash != 0, "Trivial unexpected object/monitor header usage."); } } // We finally get the hash return hash;}复制代码从以上代码片段中可以发现,实际计算hashCode的是 get_next_hash,还在这份文件中我们搜索get_next_hash,得到他的关键代码 。
static inline intptr_t get_next_hash(Thread * Self, oop obj) { intptr_t value = https://www.isolves.com/it/cxkf/yy/JAVA/2019-08-12/0 ; if (hashCode == 0) { // This form uses an unguarded global Park-Miller RNG, // so it's possible for two threads to race and generate the same RNG. // On MP system we'll have lots of RW access to a global, so the // mechanism induces lots of coherency traffic. value = os::random() ; } else if (hashCode == 1) { // This variation has the property of being stable (idempotent) // between STW operations. This can be useful in some of the 1-0 // synchronization schemes. intptr_t addrBits = cast_from_oop
推荐阅读
- 阿里架构总监13张PPT一次讲透中台架构
- 关于并发框架 Java原生线程池原理及Guava与之的补充
- 中国的收费站一天可以收多少钱 中国收费站一天的收入
- java数据结构及算法总结
- Linux中的xargs命令
- PHP删除数组中指定值的元素的方法
- 金士顿和闪迪u盘对比 金士顿u盘和闪迪u盘哪个耐用
- 茶中为什么会喝出酸味
- redis是如何存储对象和集合的
- Java中的HashCode方法与内存泄漏问题,你了解过吗?
