`

浅谈System.identityHashCode

    博客分类:
  • java
阅读更多

 

         今天在查看一下源代码的时候突然发现要调用这个函数的地方,其实如果从定义上面来看的话,感觉不是很明白,说句心里话,我的理解是这样的,它是根据对象的内存地址来生成的hashCode,比如想这么一个情景,一般来说我们都会重载hashCode函数,就那String类的hashCode来说吧,就是与字符串的内容有关系,如果我们new两个内容相同的string,那么内存地址肯定是不相同的,那么怎么才能得到原生的hashCode呢,这个函数就是干这个事情的。

      今天其实我看到了一个自己写的数据结构,就是保存一个对象和它的引用计数的。 我看的源代码是hessian,在对象序列化的时候会统计对象的引用情况,比如说Parent类,它被Child引用,它也被GrandParent引用,那么在序列化Child和GrandParent的时候,就有一个数据结构来存储Student对象被引用的情况。所以我就顺便看了一下IdenttityIntMap的函数实现:

  public class IdentityIntMap {
        private Object[] keys;
	private int[] values;

	private int prime;
	private int size;

	public IdentityIntMap(int size) {
		keys = new Object[size];
		values = new int[size];

		prime = findBiggestPrime(size);
		this.size = 0;
	}

	public int get(Object key){
		int hash = System.identityHashCode(key) % prime;
		while(true){
			Object testKey = keys[hash];
			if(testKey == null){
				return -1;
			} else if(testKey == key){
				return values[hash];
			} else {
				hash = (hash + 1) % prime;
			}
		}
	}

	public int put(Object key, int value, boolean replace) {
		int hash = System.identityHashCode(key) % prime;

		while (true) {
			Object testKey = keys[hash];
			if (testKey == null) {
				keys[hash] = key;
				values[hash] = value;
				size++;

				if (keys.length <= 4 * size) {
					resize(4 * keys.length);
				}
				return value;
			} else if (testKey != key) {
				hash = (hash + 1) % prime;
				continue;
			} else if (replace) {
				int old = values[hash];
				values[hash] = value;
				return old;
			}
		}
	}

	public int put(Object key, int value) {
		return put(key, value, true);
	}

	private void resize(int newSize) {
		int[] oldValues = values;
		Object[] oldKeys = keys;
		values = new int[newSize];
		keys = new Object[newSize];
		size = 0;

		prime = findBiggestPrime(newSize);

		for (int i = 0; i < oldKeys.length; i++) {
			if(oldKeys[i] != null){
				put(oldKeys[i], oldValues[i], true);
			}
		}
	}

	public int findBiggestPrime(int value) {
		for (int i = PRIMES.length - 1; i >= 0; i--) {
			if (PRIMES[i] <= value) {
				return PRIMES[i];
			}
		}
		return 2;
	}

	public static final int[] PRIMES = { 1, /* 1<< 0 = 1 */
	2, /* 1<< 1 = 2 */
	3, /* 1<< 2 = 4 */
	7, /* 1<< 3 = 8 */
	13, /* 1<< 4 = 16 */
	31, /* 1<< 5 = 32 */
	61, /* 1<< 6 = 64 */
	127, /* 1<< 7 = 128 */
	251, /* 1<< 8 = 256 */
	509, /* 1<< 9 = 512 */
	1021, /* 1<<10 = 1024 */
	2039, /* 1<<11 = 2048 */
	4093, /* 1<<12 = 4096 */
	8191, /* 1<<13 = 8192 */
	16381, /* 1<<14 = 16384 */
	32749, /* 1<<15 = 32768 */
	65521, /* 1<<16 = 65536 */
	131071, /* 1<<17 = 131072 */
	262139, /* 1<<18 = 262144 */
	524287, /* 1<<19 = 524288 */
	1048573, /* 1<<20 = 1048576 */
	2097143, /* 1<<21 = 2097152 */
	4194301, /* 1<<22 = 4194304 */
	8388593, /* 1<<23 = 8388608 */
	16777213, /* 1<<24 = 16777216 */
	33554393, /* 1<<25 = 33554432 */
	67108859, /* 1<<26 = 67108864 */
	134217689, /* 1<<27 = 134217728 */
	268435399, /* 1<<28 = 268435456 */
	};
}
 

 

下面的是测试方法:

 

 

public class IdentityIntMapTest {
	public static void main(String[] args) {
		IdentityIntMap intMap = new IdentityIntMap(10);
		String aaa = "aaa";
		intMap.put(aaa, 1);
		intMap.put(new String("bbb"), 2);
		intMap.put(new String("ccc"), 3);
		intMap.put(new String("ddd"), 4);
		intMap.put(new String("eee"), 5);

		System.out.println(intMap.get(aaa));
		System.out.println(intMap.get("bbb"));
	}
}

      当时我感觉到intMap.get("bbb")找不到,当时感觉到很奇怪,如果我吧IdentityIntMap的底层实现改成key.hashCode就可以了,但是后来想了一下这个数据结构的使用用途就是这样的我不能顺便修改,把今天的发现记录在这里吧。

分享到:
评论
5 楼 yizishou 2017-06-19  
为什么会
intMap.get("bbb")
找不到,因为你放进去的时候放的是
intMap.put(new String("bbb"), 2);

不是一个对象,所以肯定拿不到啦。。

所以,要么
intMap.put("bbb", 2);
intMap.get("bbb")

要么
String s = new String("bbb");
intMap.put(s, 2);
intMap.get(s)
4 楼 asialee 2013-04-22  
wushunlian 写道
bnmsmh 写道
System.identityHashCode   这个在aix平台的JDK1.7 64位环境下换算出来的hash结果为负值;这个会导致数据越界的!
为什么所有平台都返回的结果是正值,只有aix返回负值;
求解释啊!

,今天在android x86 4.2上也碰到了同样的问题

是的,有些操作系统确实会这样。
3 楼 wushunlian 2013-04-22  
bnmsmh 写道
System.identityHashCode   这个在aix平台的JDK1.7 64位环境下换算出来的hash结果为负值;这个会导致数据越界的!
为什么所有平台都返回的结果是正值,只有aix返回负值;
求解释啊!

,今天在android x86 4.2上也碰到了同样的问题
2 楼 asialee 2012-08-13  
bnmsmh 写道
System.identityHashCode   这个在aix平台的JDK1.7 64位环境下换算出来的hash结果为负值;这个会导致数据越界的!
为什么所有平台都返回的结果是正值,只有aix返回负值;
求解释啊!

你跑下这个程序,调试一下,看什么地方报错了,欢迎交流。
1 楼 bnmsmh 2012-08-13  
System.identityHashCode   这个在aix平台的JDK1.7 64位环境下换算出来的hash结果为负值;这个会导致数据越界的!
为什么所有平台都返回的结果是正值,只有aix返回负值;
求解释啊!

相关推荐

    String中==与equals区别验证

    System.out.println(System.identityHashCode(a)); System.out.println(System.identityHashCode(b)); System.out.println(System.identityHashCode(c)); ``` 每一行将打印出一个唯一的整数值,代表相应字符串实例...

    Java中堆和栈的区别

    System.out.println(System.identityHashCode(b)); System.out.println(System.identityHashCode(c)); ``` **解释**: - `a` 和 `b` 都指向了常量池中的 `"abc"` 字符串。由于它们都引用了同一个字符串对象,所以 `...

    Java Synchronized锁失败案例及解决方案

    System.out.println(thread.getName() + "------num:" + num + "---" + System.identityHashCode(num)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out....

    java.lang.System类.pdf

    Java中的`java.lang.System`类是Java核心库中不可或缺的一部分,它是系统级操作的主要入口点。这个类提供了很多静态字段和方法,用于处理系统级别的任务,如输入输出流管理、系统属性获取、时间戳获取以及资源加载等...

    Java字符串无意识的递归过程解析

    正确的做法是使用`System.identityHashCode(this)`或`Integer.toHexString(System.identityHashCode(this))`来获取并显示对象的哈希码。 总之,Java中的字符串无意识递归是指在打印或处理对象集合时,系统自动调用...

    Java是值传递,传对象引用也是通过值

    例如,可以使用Java的`System.identityHashCode()`方法来验证不同引用是否指向同一个对象,或者使用调试器来查看方法调用时的实际参数传递。 总的来说,理解Java中的值传递和对象引用传递对于编写高效、无误的代码...

    JAVA Integer类型自加实例详解

    System.out.println(System.identityHashCode(a)); a++; System.out.println(System.identityHashCode(a)); } } 输出结果表明,Integer 对象执行 ++ 操作之后,返回的是一个新的 Integer 对象。那么,为什么会...

    飞机游戏java源码-DesignSystem:设计系统

    System.identityHashCode 竞争条件 我们可以将 ArrayList 传递给接受 List 的方法吗? (不)如何解决? (使用通配符,例如 List&lt;? extends Number&gt; 以了解有关有界和无界通配符以及其他泛型问题的更多信息,请...

    麻省理工18年春软件构造课程阅读15“相等” 1

    然而,需要注意的是,Java等语言提供了像`==`这样的操作符来检查对象的引用是否相同,以及`System.identityHashCode()`来获取对象的内存地址。这些方法虽然可以揭示对象的内部状态,但并不属于ADT规范的一部分,因此...

    java面试题(较全面)

    System.out.println("Identity: C1=" + System.identityHashCode(c1) + ", C2=" + System.identityHashCode(c2) + ", C3=" + System.identityHashCode(c3)); ``` - **解释:** 上述代码展示了如何获取不同对象和...

    Java中char[]输出不是内存地址的原因详解

    Java中的char[]数组在输出时,并不像C++或其他语言那样直接显示内存地址,而是显示其内容,这是...如果你想查看对象的实际内存地址,可以使用`System.identityHashCode(object)`方法,但这通常在调试或特殊需求时使用。

    原状

    在Java中,每个对象都有一个唯一的标识,这个标识是由系统自动分配的,可以通过`System.identityHashCode()`方法来获取。理解原状对于深入理解Java中的引用、相等性和对象比较至关重要。 在Java中,有两种主要的...

    深入理解equals和hashCode方法

    它是Object类中的一个方法,默认的实现方式是:return System.identityHashCode(this);但是,我们在重写equals方法时,也需要重写hashCode方法,以保证对象的哈希码与equals方法的结果一致。 equals和hashCode的关系...

    ADP_Testing_Project:使用jUnit和Maven测试ObjectIdentity,ObjectEquality,超时和禁用测试

    对象身份测试关注的是两个对象是否指向内存中的同一个实例,这通常通过`==`运算符或`System.identityHashCode()`来检查。而对象平等性测试则考察对象是否具有相同的值,通常使用`equals()`方法和`hashCode()`方法来...

    SearchDocInstanceID

    然而,直接访问这些内存地址是不被允许的,我们可以通过`System.identityHashCode()`方法获取对象的哈希码,虽然这不是直接的内存地址,但在同一个JVM中,它能区分不同的对象实例。 2. **类与对象**:在Java中,类...

    System 类 和 Runtime 类的常用用法介绍

    System 类和 Runtime 类是 Java 核心库中的关键类,它们提供了与操作系统交互以及管理 Java 运行时环境的能力。让我们深入了解一下这两个类的常用方法和功能。 首先,System 类: 1. 获取系统环境变量: System ...

    DRUID连接池的实用 配置详解

    **默认值:** 自动生成,格式为:"DataSource-"+`System.identityHashCode(this)` **说明:** 该属性用于区分不同的数据源,在监控多个数据源的情况下,可以通过名称来进行识别。如果不进行手动配置,则系统会自动...

    数据库阿里连接池 druid配置详解

    如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this)。 jdbcUrl 配置项 jdbcUrl 配置项用于指定连接数据库的 URL,不同数据库的 URL 不一样。例如,mysql 的 URL 为:jdbc:...

Global site tag (gtag.js) - Google Analytics