Java学习之Map学习总结
Map接口及Map的实现类
1.Map接口的定义
2. Map接口的方法及使用
3.Map接口的实现类(HashMap、HashTable、TreeMap)的定义和使用
4.HashMap和Hashtable的区别
5.HashMap和HashTreeMap的区别
6.Map.entry接口
7.Collections类(用来操作集合的工具类)
1. Map接口的定义:
Map是一个映射接口,其中的每个元素都是一个key-value键值对,TreeMap、HashMap、HashTable、WeakHashMap等实现类都通过继承AbstractMap来实现,另外,不常用的HashTable直接实现了Map接口,它和Vector都是JDK1.0就引入的集合类。
2.Map接口的常用方法:
3. No. 方法或类 类型 描述
1 public void clear()
普通 清空Map集合
2 public boolean containsKey(Object key)
普通 判断指定的key是否存在
3 public boolean containsValue(Object value)
普通 判断指定的value是否存在
4 public Set<Map.Entry<K,V>>
entrySet() 普通 将Map对象变为Set集合
5 public boolean equals(Object o)
普通 对象比较
6 public V get(Object K)
普通 根据key获得value
7 public int hashCode()
普通 返回哈希码
8 public boolean isEmpty()
普通 判断集合是否为空
9 public Set<K> keySet()
普通 取得所有的key
10 public V put(K key,V value)
普通 向集合中加入元素
11 public void putAll(Map<? extends K,extends V> t)普通
将一个Map集合中的内容加入到别一个Map
12 public V remove(Object key)
普通 根据key删除value
13 public int size()
普通 取得集合长度
14 public Collection<V> values()
普通 取得全部的value Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。
二、Map接口的实现类
1.HashMap
定义:HashMap是最常用的Map类,根据键的Hash值计算存储位置,存储键值对,可以根据键获取对应值。具有很快的访问速度,但是是无序的、线程不安全的。且HashMap是线程不同步的
2、HashTable
定义:HashTable继承自Dictionary类 ,和HashMap差不多,它也是无序的,但是Hashtable是线程安全的,同步的,即任一时刻只有一个线程能写Hashtable
3. LinkedHashMap
定义:LinkedHashMap是Map中常用的有序的两种实现之一, 它保存了记录的插入顺序,先进先出。
对于LinkedHashMap而言,它继承与HashMap,底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表
4. TreeMap
定义:TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
TreeMap的排序原理是:红黑树算法的实现 。
它的主要实现是Comparator架构,通过比较的方式,进行一个排序,
三、HashMap和HashTable的区别
1. 存储结构
HashMap |
HashTable |
数组 + 链表/红黑树 |
数组 + 链表 |
HashMap的存储规则:
优先使用数组存储, 如果出现Hash冲突, 将在数组的该位置拉伸出链表进行存储(在链表的尾部进行添加), 如果链表的长度大于设定值后, 将链表转为红黑树.
HashTable的存储规则:
优先使用数组存储, 存储元素时, 先取出下标上的元素(可能为null), 然后添加到数组元素Entry对象的next属性中(在链表的头部进行添加).
出现Hash冲突时, 新元素next属性会指向冲突的元素. 如果没有Hash冲突, 则新元素的next属性就是null
2. 关于null值
HashMap |
HashTable |
key, value 均可以为 null |
key, value 均不可以为 null |
4.线程安全
HashMap |
HashTable |
线程不安全 |
线程安全 |
HashMap虽然是线程不安全的, 但还是推荐使用, 因为 HashTable实现线程安全的方式太低效了, 直接在方法上加了 synchronized 关键字来实现的.
四、HashMap和TreeMap的区别
HashMap |
TreeMap |
HashMap是基于Hash表的结构,根据键的hashCode存储数据 |
TreeMap是基于红黑二叉树的结构 |
无序存放的 |
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器 |
.HashMap允许有空键和空值 |
TreeMap不允许有空键和空值 |
五、Map.Entry
定义:Map.Entry是Map内部定义的一个接口,此接口是泛型,定义为Entry<K,V>,他表示Map集合中的一个实体(即一个Key-value对),专门用来保存Key-value的内容。
常用方法:
Public |
对象的比较 |
Public |
取得Key |
Public |
取得value |
Public |
返回哈希码 |
Public |
设置value的值 |
五、Conllections类
Collections是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。此类不能实例化。Collections中有一些工具函数,比如说sort、reverse、fill等等。
Conllections里的方法:
排序操作
1)static void
reverse(List<?> list):
反转列表中元素的顺序。(注意反转不是倒序,要进行倒序就先排序再反转)
2)static void shuffle(List<?> list) :
对List集合元素进行随机排序。
3) static void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序
4)static <T> void sort(List<T> list, Comparator<?
super T> c) :
根据指定比较器产生的顺序对指定列表进行排序。
5)static void swap(List<?> list, int i, int j)
在指定List的指定位置i,j处交换元素。
6)static void rotate(List<?> list, int distance)
当distance为正数时,将List集合的后distance个元素“整体”移到前面;当distance为负数时,将list集合的前distance个元素“整体”移到后边。该方法不会改变集合的长度。
查找、替换操作
1) static <T> int
binarySearch(List<? extends Comparable<? super T>> list, T key)
使用二分搜索法搜索指定列表,以获得指定对象在List集合中的索引。
注意:此前必须保证List集合中的元素已经处于有序状态。
2)static Object max(Collection coll)
根据元素的自然顺序,返回给定collection 的最大元素。
3)static Object max(Collection coll,Comparator comp):
根据指定比较器产生的顺序,返回给定
collection 的最大元素。
4)static Object min(Collection coll):
根据元素的自然顺序,返回给定collection
的最小元素。
5)static Object min(Collection coll,Comparator comp):
根据指定比较器产生的顺序,返回给定
collection 的最小元素。
6) static <T> void fill(List<? super T> list, T
obj) :
使用指定元素替换指定列表中的所有元素。
7)static int frequency(Collection<?> c, Object o)
返回指定 collection 中等于指定对象的出现次数。
8)static int indexOfSubList(List<?> source, List<?>
target) :
返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
9)static int lastIndexOfSubList(List<?> source, List<?>
target)
返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
10)static <T> boolean
replaceAll(List<T> list, T oldVal, T newVal)
使用一个新值替换List对象的所有旧值oldVal
案例总结
import java.util.Hashtable;
import java.util.Map;
//null值区别
private static void test() {
Map<String, String> map = new HashMap<String, String>();
//没有添加null值之前
System.out.println(“没有添加null值map的长度:”+map.size());
//添加null值
map.put(null, null);
System.out.println(“添加null值map的长度:”+map.size());
}
private static void test2() {
Map<String, String> map = new Hashtable<String, String>();
//没有添加null值之前
System.out.println(“没有添加null值map的长度:”+map.size());
//添加null值,会报空指针异常
map.put(null, null);
System.out.println(“添加null值map的长度:”+map.size());
}
public static void main(String[] args) {
test2();
}}
2、
import java.util.Hashtable;
import java.util.Map;
//null值区别
private static void test() {
Map<String, String> map = new HashMap<String, String>();
//没有添加null值之前
System.out.println(“没有添加null值map的长度:”+map.size());
//添加null值
map.put(null, null);
System.out.println(“添加null值map的长度:”+map.size());
}
private static void test2() {
Map<String, String> map = new Hashtable<String, String>();
//没有添加null值之前
System.out.println(“没有添加null值map的长度:”+map.size());
//添加null值,会报空指针异常
map.put(null, null);
System.out.println(“添加null值map的长度:”+map.size());
}
public static void main(String[] args) {
test2();
}
}
3、
import java.util.Map;
import java.util.TreeMap;
/**
* key为非系统类的对象的时候,让key对应的类实现Comparable接口并
* 重写comparable中的比较方法来规定排序的规则
*/
private static void test1() {
TreeMap<Student, String> treemap = new TreeMap<Student,String>();
Student stu1 = new Student(“张三”,”123″, 88.8);
Student stu2 = new Student(“李四”, “345”, 77);
Student stu3 = new Student(“王五”, “324”, 97);
treemap.put(stu1, stu1.getSname());
treemap.put(stu2, stu2.getSname());
treemap.put(stu3, stu3.getSname());
for (Student ele : treemap.keySet()) {
System.out.println(“姓名:”+treemap.get(ele)+”;成绩:”+ele.getScore());
}
}
/**
*为TreeMap构建一个比较器,来排序
*/
private static void test2() {
TreeMap<Student,String> treemap = new TreeMap<>(new StudentImp());
Student stu1 = new Student(“张三”,”123″, 88.8);
Student stu2 = new Student(“李四”, “345”, 77);
Student stu3 = new Student(“王五”, “324”, 97);
treemap.put(stu1, stu1.getSname());
treemap.put(stu2, stu2.getSname());
treemap.put(stu3, stu3.getSname());
for (Student ele : treemap.keySet()) {
System.out.println(“姓名:”+treemap.get(ele)+”;成绩:”+ele.getScore());
}
}
private static void test3() {
Map<String,Integer> treeMap = new TreeMap<String, Integer>();
treeMap.put(“1”, 888);
treeMap.put(“9”, 55);
treeMap.put(“31”, 777);
treeMap.put(“239”, 88);
treeMap.put(“177”, 999);
System.out.println(“使用默认排序规则,生成的结果为:” + treeMap);
Map<String, Integer> treeMap2 = new TreeMap<String,Integer>(new Comparator<String>() {
public int compare(String o1, String o2) {
//修改比较规则,按照数字大小升序排列
return Integer.parseInt(o1) – Integer.parseInt(o2);
}
});
treeMap2.put(“1”, 888);
treeMap2.put(“9”, 55);
treeMap2.put(“31”, 777);
treeMap2.put(“239”, 88);
treeMap2.put(“177”, 999);
System.out.println(“使用自定义排序规则,生成的结果为:” + treeMap2);
//由此可见,当key值中存储了Integer类型的数字时,将默认无法根据数字大小来进行排序,只有规定比较规则才能排序
}
public static void main(String[] args) {
// test1();
// test2();
test3();
}
3、实体类
private String sname;//姓名
private String sclass;//班级
private double score;//成绩
public Student(String sname, String sclass, double score) {
super();
this.sname = sname;
this.sclass = sclass;
this.score = score;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSclass() {
return sclass;
}
public void setSclass(String sclass) {
this.sclass = sclass;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public int compareTo(Student stu) {
return (int)((stu.getScore()-this.getScore())*10);
}
}
public int compare(Student o1, Student o2) {
return (int)((o1.getScore()-o2.getScore())*10);
}
测试类
/**
* 返回空的List,Set,Map集合,
* 但返回的对象是无法添加数据的.
*/
private static void testEmpty() {
List<String> allList = Collections.emptyList();
Set<String> allSet = Collections.emptySet();
Map<String,String> allMap =Collections.emptyMap();
allList.add(“Hello”);
allSet.add(“SB”);
allMap.put(“name”, “张三”);
}
private static void testAddall() {
// TODO Auto-generated method stub
List<String> all = new ArrayList<String>();
System.out.println(“——没添加内容前——–“);
System.out.println(“长度:”+all.size());
//使用addAll方法为指定集合添加内容,第一个参数为要添加内容的集合号,后面的参数为要添加的内容。
Collections.addAll(all,”aaa”,”bbb”);
System.out.println(“——添加内容后——–“);
for (String str : all) {
System.out.println(str);
}
}
/**
* public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
* 二分法搜索
*/
private static void testBinarySearch() {
List<Integer> list1 = new ArrayList<Integer>();
list1.add(2);
list1.add(3);
list1.add(1);
list1.add(4);
Collections.sort(list1);
int index1=Collections.binarySearch(list1, 2);
int index2=Collections.binarySearch(list1, 1);
System.out.println(index1);
System.out.println(index2);
System.out.println(“——–搜索不存在的——-“);
int index5=Collections.binarySearch(list1, 5);
System.out.println(index5);
}
private static void testReplaceAll() {
List<String> all = new ArrayList<String>();
all.add(“AAA”);
all.add(“BBB”);
all.add(“CCC”);
System.out.println(“———-替换之前———–“);
for (String ele : all) {
System.out.println(ele);
}
Collections.replaceAll(all, “BBB”, “bbb”);//将原来的BBB替换成bbb。
System.out.println(“———-替换之后———–“);
for (String ele : all) {
System.out.println(ele);
}
}
/**
* 使用swap()方法将集合中两个位置的内容进行交换
*/
private static void testSwap() {
List<String> all = new ArrayList<String>();
all.add(“AAA”);
all.add(“BBB”);
all.add(“CCC”);
System.out.println(“———-交换之前———–“);
for (String ele : all) {
System.out.println(ele);
}
Collections.swap(all, 0, 2);//将all集合的0位置的AAA和2位置的CCC进行交换
System.out.println(“———-交换之后———–“);
for (String ele : all) {
System.out.println(ele);
}
}
public static void main(String[] args) {
testSwap();
}
}
public static void test1() {
List<String> listS = new ArrayList<String>();
//一.将String类型的变量插入到listS中并排序
//listS中的对象String 本身含有compareTo方法,所以可以直接调用sort方法,按自然顺序排序,即升序排序
listS.add(“5”);
listS.add(“2”);
listS.add(“9”);
System.out.println(“——-排序前——-“);
for (String ele : listS) {
System.out.println(ele);
}
Collections.sort(listS);
System.out.println(“——-排序后——-“);
for (String ele : listS) {
System.out.println(ele);
}
}
/**
* 倒序
*/
private static void test2() {
List<String> list = new ArrayList<String>();
list.add(“1”);
list.add(“3”);
list.add(“2”);
System.out.println(“——-没任何操作前——-“);
for (String ele : list) {
System.out.println(ele);
}
Collections.reverse(list);
System.out.println(“——-反转后——-“);
for (String ele : list) {
System.out.println(ele);
}
Collections.sort(list);
Collections.reverse(list);
System.out.println(“——-排序后再反转——-“);
for (String ele : list) {
System.out.println(ele);
}
}
public static void main(String[] args) {
test2();
}
}