实际上,map集合和set集合非常类似,如果把Map集合中所有的Key单独来看,就组成了一个Set集合。事实上,Map中提供了keySet()方法,用于返回由key组成的Set集合。而从源码来看,Java是先实现了Map集合,然后将一个所有value都为null值得Map封装成了Set集合。如果把Map集合中的value当独来看,则与List集合很类似,元素可以重复,可以根据索引(key)来查找。
public class MapTest { public static void main(String[] args) { Map map = new HashMap(); map.put("人生得意须尽欢", 105); map.put("莫使金樽空对月", 62); map.put("古来圣贤皆寂寞", 88); // value值可以重复 map.put("唯有饮者留其名", 62); // 放入重复得key值,会覆盖原有得value值,返回被覆盖value值,62 System.out.println(map.put("莫使金樽空对月", 10)); for (Object key : map.keySet()) { // 迭代输出key值及对应value值 System.out.println(key + "-->" + map.get(key)); } } }
HashMap允许value重复,但是key值不可以重复,如果添加的key-value对中key重复了,新的value会覆盖原来的value,put方法返回原来被覆盖的value。
Hashtable也是Map的实现类,线程安全,key、value不允许存放null,而HashMap则允许。Hashtable类也过于古老,最好不要使用,而是使用Collections工具类将HashMap类变为线程安全的类。
public class NullHashMap { public static void main(String[] args) { HashMap hm = new HashMap(); hm.put(null, null); hm.put(null, null); hm.put("a", null); //{null=null, a=null} System.out.println(hm); } }
HashMap与Hashtable通过equals()和hashCode()方法比较key值是否相等,通过equals()方法比较value是否相等。
不要使用可变对象作为HashMap、Hashtable的key,否则当key被改变,会造成程序无法访问map集合中key被改变的元素。
class A { int count; public A(int count) { this.count = count; } public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == A.class) { A a = (A) obj; return this.count == a.count; } return false; } } public class HashMapErrorTest { public static void main(String[] args) { HashMap ht = new HashMap(); ht.put(new A(111), "你若精彩,蝴蝶自来"); ht.put(new A(12345), "漠漠水田飞白鹭,阴阴夏木啭黄鹂"); Iterator it = ht.keySet().iterator(); A first = (A) it.next(); first.count = 1998; // {mapdemo.A@15db9742=你若精彩,蝴蝶自来, mapdemo.A@6d06d69c=漠漠水田飞白鹭,阴阴夏木啭黄鹂} System.out.println(ht); ht.remove(new A(1998)); // {mapdemo.A@15db9742=你若精彩,蝴蝶自来, mapdemo.A@6d06d69c=漠漠水田飞白鹭,阴阴夏木啭黄鹂} System.out.println(ht); // null System.out.println(ht.get(new A(1998))); // null System.out.println(ht.get(new A(111))); } }
LinkeHashMap以双链表来维护集合中key-value对的次序,有利于迭代。
Properties类是Hashtable的子类,相当于一个key、value值都是String类型的Map,主要用于处理属性文件。
public class PropertiesTest { public static void main(String[] args) throws FileNotFoundException, IOException { Properties props = new Properties(); props.setProperty("username", "banjiu"); props.setProperty("password", "123456"); props.store(new FileOutputStream("a.ini"), "comment line"); Properties props2 = new Properties(); props2.setProperty("gender", "male"); //将a.ini文件中的key-value追加到props2中 //{password=123456, gender=male, username=banjiu} props2.load(new FileInputStream("a.ini")); System.out.println(props2); } }
Properties类可以把key-value存储至xml文件,也可以从xml文件中读取key-value对,与上示代码类似。
SortedMap的实现类TreeMap可以实现元素排序,其底层结构为红黑树。利用compareTo()方法来比较元素key大小,判断其是否相等。若使用自定义的类作为key值,则应该保证重写的equals()与compareTo()返回结果一致。
class R implements Comparable { int count; public R(int count) { this.count = count; } public String toString() { return "R[count" + count + "]"; } public boolean equals(Object obj) { if (this == obj) return true; if (obj != null && obj.getClass() == R.class) { R r = (R) obj; return r.count == this.count; } return false; } @Override public int compareTo(Object obj) { R r = (R) obj; return count > r.count ? 1 : count < r.count ? -1 : 0; } }
public class TreeMapTest { public static void main(String[] args) { TreeMap tm = new TreeMap(); tm.put(new R(3), "莫欺少年穷"); tm.put(new R(-5), "天下何人不识君"); tm.put(new R(9), "朋友一生一起走"); // {R[count-5]=天下何人不识君, R[count3]=莫欺少年穷, R[count9]=朋友一生一起走} System.out.println(tm); System.out.println(tm.lastKey()); // 比2大的最小key值 System.out.println(tm.higherKey(new R(2))); //{R[count3]=莫欺少年穷} System.out.println(tm.subMap(new R(-1), new R(4))); } }
WeakHashMap类的key为弱引用,当垃圾回收了该key所对应的实际对象后,WeakHashMap会删除对应的key-value对。
public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap whm = new WeakHashMap(); //key为匿名字符串对象 whm.put(new String("语文"), new String("良好")); whm.put(new String("数学"), new String("优秀")); whm.put(new String("英语"), new String("中")); //key为字符串直接量,系统会自动保留其强引用 whm.put("java", new String("中等")); // {java=中等, 数学=优秀, 英语=中, 语文=良好} System.out.println(whm); System.gc(); System.runFinalization(); //通常情况下,结果为{java=中等} System.out.println(whm); } }
IdentityHashMap在比较两个元素时需要key完全相等(key1==key2),而普通的HashMap仅仅需要equals()返回true且hashcode值相同。其它性质与HashMap基本类似。
```java
public class IdentityHashMapTest {
public static void main(String[] args) {
IdentityHashMap ihm = new IdentityHashMap();
// 下两行添加两个元素
ihm.put(new String(“卡布奇诺”), 99);
ihm.put(new String(“卡布奇诺”), 90);
// 下两行添加一个元素
ihm.put(“烧仙草”, 18);
ihm.put(“烧仙草”, 17);
//{卡布奇诺=99, 烧仙草=17, 卡布奇诺=90}
System.out.println(ihm);
}
}
EnumMap专门应用于枚举类,内部通过数组来实现,这种实现形式紧凑、高效;EnumMap按照自然排序(枚举值在枚举类中定义顺序)对元素进行排序;不允许key为null值。 ```java enum Season { SPRING, SUMMER, FALL, WINTER } public class EnumMapTest { public static void main(String[] args) { EnumMap ehm = new EnumMap(Season.class); ehm.put(Season.SUMMER, "夏日炎炎"); ehm.put(Season.SPRING, "春暖花开"); //{SPRING=春暖花开, SUMMER=夏日炎炎} System.out.println(ehm); } } ``` HashMap是最常用的Map集合,能够提供快速的查询,Hashtable线程安全,带来性能损耗,同时过于古老,推荐使用Collections将HashMap变成线程安全进行替代。LinkedHashMap可以维护元素的插入顺序。TreeMap对集合元素进行了排序,可以通过toArray()生成key的数组,随后用binarySearch()对元素进行快速查找。EnumMap应用于枚举类,效率最高。 这篇文章就介绍到这里了,学习集合推荐多刷题,才能够真正学会应用,个人比较推荐使用这个网站:大厂真题:[大厂面试真题大全](https://www.nowcoder.com/exam/oj?page=1&tab=%E7%AE%97%E6%B3%95%E7%AF%87&topicId=295&fromPut=pc_csdncpt_banjiu_sf)