5.Map接口:(HashMap(最常用),LinkedHashMap,Hashtable,TreeMap)
5.1.HashMap:继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口
5.1.1.根据键的HashCode值存储数据,根据键可以直接获取它的值;
5.1.2.具有很快的访问速度,遍历时,取得数据的顺序是完全随机的;
5.1.3.不支持线程的同步,线程不安全,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致
5.1.4.键和值都可以为null;
5.1.5.不允许键重复,值可以重复
(1)如果多个键重复,后面的将覆盖前面的,只保留最后一个键值对数据
(2)如果多个值重复,键唯一,将全部展示键值对数据
5.1.6.jdk1.7中为底层数组+链表实现
5.1.7.jdk1.8中改为底层数组+红黑树实现
1.代码示例:HashMap方法使用汇总
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("1", "西游记");//
hashMap.put(null, "红楼梦");
hashMap.put("2","西游记");
hashMap.put("3",null);
hashMap.put(null,null);
输出结果:{null=null, 1=西游记, 2=西游记, 3=null, 4=null}//不会显示红楼梦(前面的被覆盖了)
hashMap.clear();//作用是清空HashMap
hashMap.containsKey("1")//作用是判断HashMap是否包含key,包含为true,否则为false
hashMap.containsValue("西游记") //作用是判断HashMap是否包含value,包含为true,否则为false
hashMap.entrySet()//作用是返回“HashMap中所有Entry(key-value)的集合”,它是一个集合
System.out.println(hashMap)=System.out.println( hashMap.entrySet());
输出结果:{null=null, 1=西游记, 2=西游记, 3=null, 4=null}
hashMap.values()//作用是返回“HashMap中所有value的集合”,它是一个集合
输出结果:[null, 西游记, 西游记, null, null]
hashMap.keySet()//作用是返回“HashMap中所有key的集合”,它是一个集合
输出结果:[null, 1,2,3]
hashMap.get("1")//作用是获取key对应的value
hashMap.remove("1")//作用是删除key=1的键值对
2。遍历:可以遍历key-value,key,value三种形式
第一种:推荐(尤其量大时)
HashMap<String, String> hashMap = new HashMap<>();
for(Map.Entry<String, String> entry: hashMap .entrySet())
{
System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());
}
第二种:显示调用map.entrySet()的集合迭代器
Iterator<Map.Entry<String, String>> iterator=hashMap .entrySet().iterator();
while(iterator.hasNext())
{
Map.Entry<String, String> entry=(Entry<String, String>)iterator.hasNext();
System.out.println("Key: "+entry.getKey()+" Value: "+entry.getValue());
}
第三种:分别获取key,value
for(String key:map.keySet())
{
System.out.println("Key: "+key+" Value: "+map.get(key));
}
第四种:获取value
for(String v:map.values())
{
System.out.println("The value is "+v);
}
实际应用中前两种效率高!!!
5.2.Hashtable:继承自Dictionary类
5.2.1.支持线程同步,即同一时刻只能有一个线程对hashtable进行操作(这导致了它的写入较慢)
5.2.2.不允许键或值为空
5.2.3.jdk1.7中为底层数组+链表实现
5.2.4.jdk1.8中改为底层数组+红黑树实现
5.3. LinkedHashMap:是HashMap的一个子类,用法和HashMap一样
5.3.1.当希望有顺序地去存储key-value时,就需要使用LinkedHashMap了(默认为插入顺序)
插入时什么顺序,输出时就是什么顺序!
代码示例:
(1)使用HashMap
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("1", "西游记");
hashMap.put("2", "红楼梦");
hashMap.put("3", "水浒传");
for(Map.Entry<String, String> entry: hashMap .entrySet())
{
System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());
}
可能会输出: Key:3 Value:水浒传
Key:1 Value:西游记
Key:2 Value:红楼梦
(2)使用LinkedHashMap
LinkedHashMap <String, String> linkedHashMap = new LinkedHashMap <>();
linkedHashMap .put("1", "西游记");
linkedHashMap .put("2", "红楼梦");
linkedHashMap .put("3", "水浒传");
for(Map.Entry<String, String> entry: linkedHashMap .entrySet())
{
System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());
}
一定输出: Key:1 Value:西游记
Key:2 Value:红楼梦
Key:3 Value:水浒传
5.4.TreeMap:继承于AbstractMap(了解)
5.4.1.通过红黑树实现的,本质是R-B Tree(红黑树),它包含几个重要的成员变量: root, size, comparator
root: (1) 是红黑数的根节点。它是Entry类型,Entry节点根据key进行排序,节点包含的内容为value
(2)包含了红黑数的6个基本组成成分:key(键)、value(值)、left(左孩子)、right(右孩子)、parent(父节点)、color(颜色)
size:是红黑数中节点的个数
comparator:Entry中的key比较大小是根据比较器comparator来进行判断的
5.4.2.是非同步的
5.4.3.不允许key=null,允许value=null
代码示例:
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("1", "西游记");
treeMap.put("4", "红楼梦");
treeMap.put("2",null);
treeMap.put("3",null);
//treeMap.put(null,null);
for(Entry<String, String> entry: treeMap .entrySet())
{
System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());
}
输出:Key: 1 Value: 西游记
Key: 2 Value: null
Key: 3 Value: null
Key: 4 Value: 红楼梦
扩展:Map接口的同步实现
(1)可以使用Hashtable实现类;
1.采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作
(2)可以使用SynchronizedMap实现类
(3)可以使用java.util.concurrent包提供的ConcurrentHashMap
1.jdk1.7中采用了数组+Segment+分段锁的方式实现,线程安全
2.jdk1.8中采用了数组+链表+红黑树的实现方式来设计,内部大量采用CAS操作
2.通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认将hash表分为16个桶
3.是使用了锁分段技术来保证线程安全的
锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,
其他段的数据也能被其他线程访问。
4.诸如get、put、remove等常用操作只锁住当前需要用到的桶。原来只能一个线程进入,现在却能同时有16个写线程执行,
并发性能的提升是显而易见的
扩展:CAS是compare and swap的缩写,即我们所说的比较交换
(1)cas是一种基于锁的操作,而且是乐观锁
在java中锁分为乐观锁和悲观锁:
悲观锁:是将资源锁住,等之前获得锁的线程释放锁之后,下一个线程才可以访问
乐观锁:采取了一种宽泛的态度,通过某种方式不加锁来处理资源,性能较悲观锁有很大的提高
(2)cas包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)
如果内存地址里面的值V和预期原值A的值是一样的,那么就将内存里面的值更新成B