[疯狂Java]集合:IdentityHashMap、EnumMap

翻译 2016年05月31日 21:54:24

1. IdentityHashMap:

    1) 是一种特殊的HashMap,还是用key的hashCode来决定entry的槽位,但是不用key的equals方法来决定是否相等了,而是默认使用地址(即使实现了equals,equals也不起作用)来决定是否相等了!

    2) 所以叫做Identity,就是直接用内存地址严格定义相等;

!!但是IdentityHashMap允许key和value都为null

    3) 示例:

class R {
	int val;

	public R(int val) {
		this.val = val;
	}

	@Override
	public String toString() {
		return "R[val:" + val + "]";
	}

	@Override
	public boolean equals(Object obj) { // equals的标准写法
		if (this == obj) { // 先比较地址
			return true;
		}
		
		if (obj != null && obj.getClass() == R.class) { // 再比较类型(前提是obj不能为空)
			R r = (R)obj; // 先把类型调整一致(当然可以直接return this.val == ((R)obj).val
						  // 但如果在return之前还要用obj进行一些其它复杂操作那用临时的类型转换太麻烦了
			              // 因此先协调类型才是最标准最合理的做法
			return this.val == r.val;
		}
		
		return false; // 地址不同 || obj为空 || 类型不一致,那肯定不一样了!
	}

	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.val;
	}
	
	
}

public class Test {
	
	public static void main(String[] args) {
		IdentityHashMap map = new IdentityHashMap<>();
		map.put(new R(1), "fun");
		map.put(new R(1), "kun");
		R r = new R(3);
		map.put(r, "xxx");
		map.put(r, "yyy");
		System.out.println(map); // {R[val:1]=fun, R[val:3]=yyy, R[val:1]=kun}
		
		IdentityHashMap map2 = new IdentityHashMap<>();
		map2.put(new String("lala"), "abc");
		map2.put(new String("lala"), "xyz");
		map2.put("mama", "777");
		map2.put("mama", "888");
		System.out.println(map2); // {mama=888, lala=xyz, lala=abc}
	}
}


!!可以发现R的equals不起做用了,而String也实现了equals,同样也不起作用,但是两个"mama"的key没有重复,因为常量字符串是保存在内存常量池中的,因此地址相同;

    4) IdentityHashMap的使用规矩:

         i. 可以看到,它强行把地址的equals当equals方法用了!!

         ii. 而我们之前说过,使用HashMap的原则是equals和hashCode要保持一致,因此我们使用IdentityHashMap的时候就应该让hashCode和地址相等保持一致!!

         iii. 总结:用IdentityHashMap存放的元素最好不重写equals和hashCode(默认从Object继承来的都是直接比较地址,而hashCode返回的就是地址);

!!否则就会像上面的例子一样,equals相等并且hashCode也相等的情况下也出现了元素重复的现象!!这就非常混乱了!!

!!也就是说使用IdentityHashMap保存的元素最好是彻彻底底地根据地址判断是否相等!!!


2. EnumMap:

    1) 和EnumMap类似,只不过要求key必须是枚举类型的值,并且key的枚举类型必须一致(所有元素的key必须都属于同一种枚举类型!),但value的类型随意(Object、String、自定义类型什么的随意);

    2) 构造器:

         i. 不像EnumSet构造时是通过各种静态工具方法构造,EnumMap必须用构造器构造;

         ii. 这里只介绍最常用的版本:EnumMap(Class<K> keyType);  // 用key的类型构造,例如:EnumMap map = new EnumMap(Season.class);

    3) 和EnumSet不允许元素为null一样,EnumMap不允许key为null,但是value无所谓,因为key就代表了entry!但是判空、删除null的方法都能正常使用;

    4) 接下来就可以把EnumMap当成普通Map使用了,可以使用所有Map里有的方法,示例:

enum Season {
	SPRING, SUMMER
}

public class Test {
	public static void main(String[] args) {
		EnumMap map = new EnumMap<>(Season.class);
		map.put(Season.SPRING, "lala");
		map.put(Season.SUMMER, Integer.valueOf(11));
		System.out.println(map);
	}
}
     5) 由于EnumSet、EnumMap都是使用二进制为向量进行映射的(EnumMap映射是通过key映射)的,因此不用担心重复问题,毕竟枚举类型也没有equals、hashCode一说;

Java中的枚举——EnumMap与EnumSet

为了更好的支持枚举类型,java.util中添加了两个新类:EnumMap和EnumSet。使用它们可以更高效的操作枚举类型。下面我一一介绍给你:     EnumMap是专门为枚举类型量身定做的M...
  • u012927198
  • u012927198
  • 2015年04月10日 14:09
  • 1063

Enum、EnumMap、EnumSet的用法讲解

今天在工作中遇到这样一个问题,要在前台页面上渲染出来所有的枚举元素,但是前台页面用的是Velocity,所以需要把枚举元素放到Map里,然后在前台进行渲染。这里不能一个一个的取出枚举元素来put的,就...
  • zknxx
  • zknxx
  • 2016年07月11日 23:47
  • 8366

Java EnumMap 代替序数索引

学习笔记《Effective Java 中文版 第2版》经常会碰到使用Enum的ordinal方法来索引枚举类型。public class Herb { public enum Type { ...
  • chy555chy
  • chy555chy
  • 2016年12月20日 17:26
  • 300

Java集合框架:EnumMap

EnumMap的key不允许为null,value可以为null,按照key在enum中的顺序进行保存,非线程安全。可以用工具类Collections进行包装成线程安全的: ``` Map m = C...
  • u013256816
  • u013256816
  • 2016年03月17日 19:59
  • 4550

java求无重复集合所有子集

在lintcode上遇到一道题,如下: 给定一个含不同整数的集合,返回其所有的子集 注意事项: 子集中的元素排列必须是非降序的,解集必须不包含重复的子集。...
  • yinglish_
  • yinglish_
  • 2016年09月10日 23:32
  • 1274

编写一个方法,返回某集合的所有子集

ArrayList> getSubsets(ArrayList set,int index) { ArrayList> allsubsets; if(set.size()==index)//终止...
  • wangfengfan1
  • wangfengfan1
  • 2015年08月29日 20:45
  • 696

Java中如何遍历Map对象

博主有时会忘记如何遍历Map对象,这次在这里做一下总结。博主采用的是JDK7,先看一下JDK7中Map接口的定义。 java.util Interface Map 类型参数:K - th...
  • u013256816
  • u013256816
  • 2015年12月14日 15:04
  • 7815

【Java】通过位运算求一个集合的所有子集

Java没有自带的求一个集合的所有子集的方法,我们可以通过集合的子集规律来求。 一个集合的所有子集等于2^该集合的长度。比如{c,b,a}的长度为3,这个集合的子集就有8个。 这句话看起来很简单,...
  • yongh701
  • yongh701
  • 2016年12月12日 15:50
  • 1497

EnumMap源码阅读

EnumMap的键值必须是Enum类型,而且put的时候只能是初始化时指定的Enum或者其子类型。同时不支持键值为null。 EnumMap初始化会创建存放key和value的两个数组,大小为Enum...
  • changer328
  • changer328
  • 2014年11月19日 20:21
  • 767

EnumMap类源码解析

EnumMap 内部通过数组存在元素 key:表示的是枚举类型,这个类型要一样 用value存储枚举具体的存储值 通过ordinal方法,使得有序存储 package java.util;im...
  • qunxingvip
  • qunxingvip
  • 2016年07月17日 10:36
  • 1201
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[疯狂Java]集合:IdentityHashMap、EnumMap
举报原因:
原因补充:

(最多只允许输入30个字)