Map 接口(重点)
如果现在假设要操作一对对象,类似于以 下一种情况:
张三 123456
李四 234567
保存以上信息的时候使用 Collection 就不那么方便,所以要使用 Map 接口。里面的所有内容都按照 key–>value 的形式保存,也称为二元偶对象。
此接口定义如下:
public interface Map<K,V>
此接口与 Collection 接口没有任何的关系,是第二大的集合操作接口。此接口常用方法如下:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | void clear() | 普通 | 清空 Map 集合中的内容 |
2 | boolean containsKey(Object key | 普通 | 判断集合中是否存在指定的 key |
3 | boolean containsValue(Object value) | 普通 | 判断集合中是否存在指定的 value |
4 | Set<Map.Entry<K,V>> entrySet() | 普通 | 将 Map 接口变为 Set 集合 |
5 | V get(Object key) | 普通 | 根据 key 找到其对应的 value |
6 | boolean isEmpty() | 普通 | 判断是否为空 |
7 | Set keySet() | 普通 | 将全部的 key 变为 Set 集合 |
8 | Collection values() | 普通 | 将全部的 value 变为 Collection 集合 |
9 | V put(K key,V value) | 普通 | 向集合中增加内容 |
10 | void putAll(Map<? extends K, ? extends V> m) | 普通 | 增加一组集合 |
11 | V remove(Object key) | 普通 | 根据 key 删除内容 |
Map 本身是一个接口,所以一般会使用以下的几个子类:HashMap、TreeMap、Hashtable
新的子类:HashMap(重点)
HashMap 是 Map 的子类,此类的定义如下:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
此类继承了 AbstractMap 类,同时可以被克隆,可以被序列化下来。
向集合中增加内容:
public class HashMapDemo01 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(1, "张三B"); // 新的内容替换掉旧的内容
map.put(2, "李四");
map.put(3, "王五");
String val = map.get(6);
System.out.println(val);
}
}
以上的操作是 Map 接口在开发中最基本的操作过程,根据指定的 key 找到内容,如果没有找到,则返回 null,找到 了则返回具体的内容。
得到全部的 key 或 value :
public class HashMapDemo02 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "张三A");
map.put(2, "李四");
map.put(3, "王五");
Set<Integer> set = map.keySet(); // 得到全部的key
Collection<String> value = map.values(); // 得到全部的value
Iterator<Integer> iter1 = set.iterator();
Iterator<String> iter2 = value.iterator();
System.out.print("全部的key:");
while (iter1.hasNext()) {
System.out.print(iter1.next() + "、");
}
System.out.print("\n全部的value:");
while (iter2.hasNext()) {
System.out.print(iter2.next() + "、");
}
}
}
既然可以取得全部的 key,那么下面就可以对以上的操作进行扩充,循环输出 Map 中的全部内容。
public class HashMapDemo03 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到key
System.out.println(i + " --:> " + map.get(i));
}
}
}
HashMap 本身是属于无序存放的。
旧的子类:Hashtable(重点)
Hashtable 是一个最早的 key–>value 的操作类,本身是在 JDK 1.0 的时候推出的。其基本操作与 HashMap 是类似的。
public class HashtableDemo01 {
public static void main(String[] args) {
Map<String, Integer> numbers = new Hashtable<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
Integer n = numbers.get("two");
if (n != null) {
System.out.println("two = " + n);
}
}
}
操作的时候,可以发现与 HashMap 基本上没有什么区别,而且本身都是以 Map 为操作标准的,所以操作的结果形式 都一样。但是 Hashtable 中是不能向集合中插入 null
HashMap 与 Hashtable 的区别(重点)
在整个集合中除了 ArrayList 和 Vector 的区别之外,另外一个最重要的区别就是 HashMap 与 Hashtable 的区别。
No. | 区别点 | HashMap | Hastable |
---|---|---|---|
1 | 推出时间 | JDK 1.2 之后推出的,新的操作类 | JDK 1.0 时推出的,旧的操作类 |
2 | 性能 | 异步处理,性能较高 | 同步处理,性能较低 |
3 | null | 允许设置为 null | 不允许设置,否则将出现空指向异常 |
区别总结:
1.区别:
(1)HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全;
(2)HashMap允许key和value为null,而HashTable不允许2.底层实现:数组+链表实现
jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在
- 计算key的hash值,二次hash然后对数组长度取模,对应到数组下标,
- 如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组,
- 如果产生hash冲突,先进行equa比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表
- key为null,存在下标0的位置
排序的子类:TreeMap(理解)
TreeMap 子类是允许 key 进行排序的操作子类,其本身在操作的时候将按照 key 进行排序,另外,key 中的内容可以 为任意的对象,但是要求对象所在的类必须实现 Comparable 接口。
public class TreeMapDemo01 {
public static void main(String[] args) {
Map<String, String> map = new TreeMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<String> set = map.keySet(); // 得到全部的key
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String i = iter.next(); // 得到key
System.out.println(i + " --:> " + map.get(i));
}
}
}
此时的结果已经排序成功了,但是从一般的开发角度来看,在使用 Map 接口的时候并不关心其是否排序,所以此类 只需要知道其特点即可。
关于 Map 集合的输出
在 Collection 接口中,可以使用 iterator()方法为 Iterator 接口实例化,并进行输出操作,但是在 Map 接口中并没有此 方法的定义,所以 Map 接口本身是不能直接使用 Iterator 进行输出的。
因为 Map 接口中存放的每一个内容都是一对值,而使用 Iterator 接口输出的时候,每次取出的都实际上是一个完整的 对象。如果此时非要使用 Iterator 进行输出的话,则可以按照如下的步骤进行: 1、 使用 Map 接口中的 entrySet()方法将 Map 接口的全部内容变为 Set 集合
2、 可以使用 Set 接口中定义的 iterator()方法为 Iterator 接口进行实例化
3、 之后使用 Iterator 接口进行迭代输出,每一次的迭代都可以取得一个 Map.Entry 的实例
4、 通过 Map.Entry 进行 key 和 value 的分离
那么,到底什么是 Map.Entry 呢?
Map.Entry 本身是一个接口。此接口是定义在 Map 接口内部的,是 Map 的内部接口。此内部接口使用 static 进行定义, 所以此接口将成为外部接口。
实际上来讲,对于每一个存放到 Map 集合中的 key 和 value 都是将其变为了 Map.Entry 并且将 Map.Entry 保存在了 Map 集合之中。
在 Map.Entry 接口中以下的方法最为常用:
No. | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | K getKey() | 普通 | 得到 key |
2 | V getValue() | 普通 | 得到 value |
使用 Iterator 输出 Map 接口
public class MapOutDemo01 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
Set<Map.Entry<String, String>> set = map.entrySet();// 变为Set实例
Iterator<Map.Entry<String, String>> iter = set.iterator();
while (iter.hasNext()) {
Map.Entry<String, String> me = iter.next();
System.out.println(me.getKey() + " --> " + me.getValue());
}
}
}
以上的代码一定要记住,Map 集合中每一个元素都是 Map.Entry 的实例,只有通过 Map.Entry 才能进行 key 和 value 的分离操作。
除了以上的做法之外,在 JDK 1.5 之后也可以使用 foreach 完成同样的输出,只是这样的操作基本上不使用。
public class MapOutDemo02 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ZS", "张三");
map.put("LS", "李四");
map.put("WW", "王五");
map.put("ZL", "赵六");
map.put("SQ", "孙七");
for (Map.Entry<String, String> me : map.entrySet()) {
System.out.println(me.getKey() + " --> " + me.getValue());
}
}
}