hashCode

  1. 说明:在探察struts2 IOC容器的内存维护(强、软、弱、虚引用时),难免会用到 Map(HashMap),那么hashCode跑出来了,这东西都忘记了。
    只好一边回忆代码一边注释,就没组织编排了。。。
  2. 能力有限,有误差的请包含或指证
  3. 目的:分享 ,交流。
  4. 内容:以下为主代码内容
    相关图片:
    这里写图片描述
    这里写图片描述

主代码和注释如下:

 package org.yl.grammar;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

import org.yl.domain.User;

/**
 * hashCode语法SAMPLE
 * 
 * >>>>>Object对象中的hashCode()方法>>>>>
	作用:返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。 
	
	hashCode 的常规协定是: 
	(1)在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 	
		比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 

	(2)如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。 

	(3)如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 	
		要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。 
		
	 说明:a).**Object中的hashCode()方法算法是:将对象的内部地址转换为整数,
	 那么调用Object中的hashCode()方法(即未被重写的hashCode方法)
	 返回的值相等,那么对象一定相等(这里的相等指的是Object中的equals方法即==判断),除非
	 这里的地址官方说指的是逻辑地址,同一块内存中相同地址的数据在同一时刻必定相等。**
		  b).为什么要有上面的约定,目的是提高哈希表的性能
		  c).当判定一个对象是否相等时(或者说是否为同一个对象时),一定查看该对象是否重写了Object类中的equals和hashCode两个方法,
			若重写了,则根据多态特性看看实际处理中调用的是那个对象下的equals和hashCode方法,来判断对象是否相等。
			
	 (4)哈希表也称散列表,使用散列算法来映射地址,存取值时以散列映射的地址作为寻址地址而不直接用equal效率必然得到本质上的提升
	 		比如:散列算法得到一个index=6作为数组tab[]的下标,取这个元素就非常简单了tab[index]
	 		应用场景:testHashtable();这就是为什么作为Key的对象需要hashCode和equals方法的原由
	 		HashMap与Hashtable底层实现是相同的,这里就不再敖述。
	 		
	 (5)结合hashCode和equals方法来处理Set集合的无重复特性:
	 		通常判断一个集合中的元素是否重复,都会使用equals方法判断是否相等
	 		若相等则不存入,不相等则存入(add)。这样做就有一个很大的问题,效率问题。
	 		比如Set元素中有1万个元素了,那么添加新元素得判断1万次。那么有没有一种方法解决这个问题呢?
	 		HashSet底层就采用了哈希表的原理,使用散列算法(哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上)
	 		
	 		当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 
		如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;
		如果这个位置上已经有元素了且hashCode值相等就调用它的equals方法与新元素进行比较,
			相同的话就不存了,只对value进行覆盖,然后立即return value。
			不相同的话,遍历该元素的链表的下一个节点,直到节点为空 
		这样问题就解决了,细细想想这么一来实际调用equals方法的次数就大大降低了
	 
	 		
	 (6).散列算法核心: 尽量散列开,去重复。
	 
 * @author 拈花为何不一笑
 *
 */
public class HashCodeGram {

	/**
	 * 单元测试
	 * @param args
	 */
	public static void main(String[] args) {

		//Object中的hashCode()方法算法是:将对象的内部地址转换为整数
		User user = new User();
		User user2 = user;
		testObjectHashCode(user);
		testObjectHashCode(user2);
		
		//System中的hash算法
		tesetSystemHashCode(user);
		
		//hashCode和equals方法应用一
		testHashtable();
		testMod();
		
		//hashCode和equals方法应用二
		testHashSet();
	}

	/**
	 * HashSet底层采用的HashMap来实现
	 * 	源码片段:
	 * 	int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
             
             // 当:e == null时,说明table[i]中没有存数据,直接结束循环,添加Entry
              * 当:e != null时,通过散列算法,直接与数据元素table[i]比较:
              *  e.hash == hash,
              * 	而不是与整个数据进行比较,比较相同时再用equals比较链表下的key
             //HashSet的add(E e1)方法中e1作为key被存储在Map中的
             //取值时,实际取的是map中的key:map.keySet().iterator()
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;//key相等直接返回,不用再创建新的Entry
            }
        }
        
        addEntry(hash, key, value, i);
        addEntry(int hash, K key, V value, int bucketIndex){
        	Entry<K,V> e = table[bucketIndex];
        	table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        }
	 *  
	 *  取值:hashSet.iterator();
	 *  	 map.keySet().iterator()
	 */
	private static void testHashSet() {
		Set<String> hashSet = new HashSet<String>();
		//存取
		hashSet.add("hello");
		hashSet.iterator();
		 
		
	}

	/**
	 * Hashtable底层实现哈希表
	 * 	put(k,v)时,对key进行散列算法hashCode和取模得到index
	 * 根据散列值index,给数组tab[index]定义元素Entry<K,V>
	 * 	比如:Entry<K,V>: tab[2] = new Entry<K,V>(...);
	 * 而Entry<K,V>又是一个链表
	 * 	源码片段:
	 * 		1.散列算法:
	 * 		  int hash = key.hashCode();
	 *		  int index = (hash & 0x7FFFFFFF) % tab.length;
	 *		2.创建一个新的Entry并作为Entry[]数组,index为数组下标
	 * 			Entry<K,V> e = tab[index];
	 * 			tab[index] = new Entry<K,V>(hash, key, value, e);
	 * 		3.如果Key的hashCode相同,且Key的equal也相同则视Key为同一个对象,
	 * 			给原来的v进行覆盖并立即返回
	 * 			if ((e.hash == hash) && e.key.equals(key)) {
	 *					V old = e.value;
	 *					e.value = value;
	 *					return old;
	 *			    }
	 *		4.遍历链表下的节点Entry是否为同一个对象,如果是,那么进行Value覆盖
	 *			for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
					    if ((e.hash == hash) && e.key.equals(key)) {
							V old = e.value;
							e.value = value;
							return old;
				 		}
				 }
			 遍历完成后,tab[index]节点的链表,在其头部插入新的Entry(图:hashtable存储过程)
			 	Entry<K,V> e = tab[index];
				tab[index] = new Entry<K,V>(hash, key, value, e);
	 *
	 * 二、取值时也用到Key对象的hashCode和equals方法
	 * 		get(Object key):
	 * 		int hash = key.hashCode();
	 * 		int index = (hash & 0x7FFFFFFF) % tab.length;
	 * 		for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
	 * 			if ((e.hash == hash) && e.key.equals(key)) {
	 * 				return e.value;
	 *  		}
	 *  	}
	 *  
	 */
	private static void testHashtable() {
		Map<String,Object> a = new Hashtable<String,Object>();
		//存取操作
		a.put("aKey", 2);
		a.get("aKey");
		
	}


	/**
	 * 取模(%)
	 */
	private static void testMod() {
		int[] iArray = new int[]{
				0,1,2,3,4,5,6,7,8,9,10,
				101,102,103,104,105,106,107,108,109,110,
				3006,8009,10024
				};
		for (int i = 0; i < iArray.length; i++) {
			int mod = iArray[i] % 10;
			System.out.println("mod:" + iArray[i] + "% 10 = "+ mod);
		}
		
	}


	/**
	 * 调用System.identityHashCode(user)
	 * 不论调用多少次,只要是同一个user,返回的值uhascode也一样
	 * 作用:当用户自定义类重写了Object类的hashCode()方法时,
	 * 	又想使用其它hashCode方法时,此方法与Object类中的hashCode()
	 * 	方法是等效的。
	 */
	private static void tesetSystemHashCode(User user) {
		int uhashcode = System.identityHashCode(user);
		System.out.println(uhashcode);
		
	}

	/**
	 * 
	 * 调用Object的hashCode()方法算法:通常是通过将对象的内部地址转换为整数来实现的
	 * 两次输出:12677476 ,33263331。
	 * 每次run as->java application都重新new User(),所以是不同的user实例的
	 * hashCOde值
	 * 
	 */
	private static void testObjectHashCode(User user) {
		int userHashCode = user.hashCode();
		System.out.println(userHashCode);
		
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值