Java学习13-集合-2
文章目录
7.Map接口
7.1 Map接口概述
- Map与Collection并列存在。用于保存具有 映射关系的数据:key-value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 key 用Set来存放, 不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法
- 常用String类作为Map的“键”
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value
- Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和Properties。其中,HashMap是 Map 接口使用频率最高的实现类
7.2 Map接口:常用方法
- 添加 、 删除、修改操作 :
- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- Object remove(Object key):移除指定key的key-value对,并返回value
- void clear():清空当前map中的所有数据
- 元素查询的操作:
- Object get(Object key):获取指定key对应的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中key-value对的个数
- boolean isEmpty():判断当前map是否为空
- boolean equals(Object obj):判断当前map和参数对象obj是否相等
- 元素视图操作的方法:
- Set keySet():返回所有key构成的Set集合
- Collection values():返回所有value构成的Collection集合
- Set entrySet():返回所有key-value对构成的Set集合
【例】
import java.util.*;
public class MapTest {
public static void main(String[] args) {
MapTest mt = new MapTest();
// mt.test1();
//mt.test2();
mt.test3();
}
/**
* 添加、删除、修改
* - Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
* - void putAll(Map m):将m中的所有key-value对存放到当前map中
* - Object remove(Object key):移除指定key的key-value对,并返回value
* - void clear():清空当前map中的所有数据
*/
public void test1() {
Map map = new HashMap();
//put()
map.put("AA",123);
map.put("BB",45);
map.put("DD",78);
map.put("CC",67);
//put()
map.put("DD",89);
System.out.println(map);
//{AA=123, BB=45, DD=89, CC=67}
Map map1 = new HashMap();
map1.put("aa",123);
map1.put("bb",123);
//putAll()
map.putAll(map1);
System.out.println(map);
//{AA=123, BB=45, DD=89, CC=67, aa=123, bb=123}
//remove()
Object cc = map.remove("CC");
System.out.println(cc);//67
System.out.println(map);//{AA=123, BB=45, DD=89, aa=123, bb=123}
//clear()
map.clear();//与map = null操作不同
System.out.println(map);//{}
System.out.println(map.size());//0
}
/**
* 元素查询的操作:
* - Object get(Object key):获取指定key对应的value
* - boolean containsKey(Object key):是否包含指定的key
* - boolean containsValue(Object value):是否包含指定的value
* - int size():返回map中key-value对的个数
* - boolean isEmpty():判断当前map是否为空
* - boolean equals(Object obj):判断当前map和参数对象obj是否相等
*/
public void test2() {
Map map = new HashMap();
map.put("AA",123);
map.put("BB",45);
map.put("DD",78);
map.put("CC",123);
map.put("DD",89);
Map map1 = new HashMap();
map1.put("AA",123);
map1.put("BB",45);
map1.put("DD",78);
map1.put("CC",123);
map1.put("DD",89);
//get()
System.out.println(map.get("AA"));//123
//containsKey()
System.out.println(map.containsKey("BB"));//true
//containsValue()
System.out.println(map.containsValue(123));//true
//size()
System.out.println(map.size());//4
//isEmpty()
map.clear();
System.out.println(map.isEmpty());//true
//equals()
System.out.println(map.equals(map1));//false(地址不同)
}
/**
* 元素视图操作的方法:
* - Set keySet():返回所有key构成的Set集合
* - Collection values():返回所有value构成的Collection集合
* - Set entrySet():返回所有key-value对构成的Set集合
*/
public void test3(){
Map map = new HashMap();
map.put("AA",123);
map.put("BB",45);
map.put("DD",78);
map.put("CC",123);
map.put("DD",89);
//遍历所有的key集:keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
// AA
// BB
// DD
// CC
}
System.out.println();
//遍历所有的value集:values()
Collection values = map.values();
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
// for (Object obj:values) {
// System.out.println(obj);
// }
// 123
// 45
// 89
// 123
System.out.println();
//遍历所有的key-value集:
// 方式一:entrySet()
Set set1 = map.entrySet();
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()){
Object obj=iterator2.next();
Map.Entry entry=(Map.Entry)obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
// AA--->123
// BB--->45
// DD--->89
// CC--->123
System.out.println();
//方式二:
Set set2 = map.keySet();
Iterator iterator3 = set2.iterator();
while (iterator3.hasNext()){
Object next = iterator3.next();
Object o = map.get(next);
System.out.println(next + "--->" + o);
}
// AA--->123
// BB--->45
// DD--->89
// CC--->123
}
}
7.3 Map 实现类之一:HashMap(重要)
- HashMap是 Map 接口使用频率最高的实现类。效率高,但是线程不安全
- 允许使用null键和null值,与HashSet一样,不保证映射的顺序。
- 所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写:equals()和hashCode()
- 所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()
- 一个key-value构成一个entry
- 所有的entry构成的集合是Set:无序的、不可重复的
- HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCode 值也相等。
- HashMap 判断两个 value 相等的标准是:两个 value 通过 equals() 方法返回 true。
HashMap的底层实现原理:
HashMap map = new HashMap();
在实例化以后,底层创建了长度是16的一维数组Entry[ ] table
map.put(key1, value1);
- 首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到Entry数组中的存放位置:
- 如果此位置上的数据为空,此时的key1-value1添加成功--------->情况1
- 如果此位置上的数据不为空(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
- 如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value添加成功-------->情况2
- 如果key1的哈希值与已经存在的某一个数据(key2-value)的哈希值相同,继续比较:调用key1所在类的equals(key2)
- 如果equals()返回false:此时key1-value1添加成功-------->情况3
- 如果equals()返回true:使用value1 替换 value2
补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储
在不断地添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来
jdk8 相较于 jdk7在底层实现方面的不同
- new HashMap():底层没有创建一个长度为16的数组
- jdk 8 底层的数组是Node[ ] ,而非Entry[ ]
- 首次调用put()方法时,底层创建长度为16的数组
- jdk 7 底层结构只有:数组+链表。jdk 8 中底层结构:数组+链表+红黑树
当数组的某一个索引位置上的元素以链表形式存在的数据个数 >8 且当前数组的长度 >64时,此时索引位置上的所有数据使用红黑树存储(优化查找效率)
7.4 Map 实现类之二:LinkedHashMap
- LinkedHashMap 是 HashMap 的子类
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序,使得在遍历map时,可以按照添加的顺序遍历
- 执行效率高于HashMap
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
MapTest mt = new MapTest();
mt.test1();
mt.test2();
}
public void test1() {
Map map = new HashMap();
map.put(123, "AA");
map.put(456, "BB");
map.put(12, "CC");
System.out.println(map);//{456=BB, 123=AA, 12=CC}
}
public void test2() {
Map map = new LinkedHashMap();
map.put(123, "AA");
map.put(456, "BB");
map.put(12, "CC");
System.out.println(map);//{123=AA, 456=BB, 12=CC}
}
}
7.5 Map 实现类之三:TreeMap
- TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。
- TreeSet底层使用 红黑树结构存储数据
- TreeMap 的 Key 的排序:
- Key的自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
- Key的定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口
- TreeMap判断两个key 相等的标准:两个key通过compareTo()方法或者compare()方法返回0。
【例】
import java.util.*;
public class TreeMapTest {
//向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
//因为要按照key进行排序:自然排序、定制排序
public static void main(String[] args) {
TreeMapTest treeMapTest = new TreeMapTest();
treeMapTest.test1();
System.out.println();
treeMapTest.test2();
}
/**
* 自然排序
*/
public void test1() {
TreeMap treeMap = new TreeMap();
User user1 = new User("Tom", 23);
User user2 = new User("Jack", 37);
User user3 = new User("Jerry", 28);
User user4 = new User("Rose", 32);
treeMap.put(user1, 98);
treeMap.put(user2, 78);
treeMap.put(user3, 88);
treeMap.put(user4, 97);
Set set1 = treeMap.entrySet();
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()) {
Object obj = iterator2.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
// User{name='Jack', age=37}--->78
// User{name='Jerry', age=28}--->88
// User{name='Rose', age=32}--->97
// User{name='Tom', age=23}--->98
}
/**
* 定制排序
*/
public void test2() {
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof User && o2 instanceof User) {
User u1 = (User) o1;
User u2 = (User) o2;
return Integer.compare(u1.getAge(), u2.getAge());
}
throw new RuntimeException("输入的类型不匹配");
}
});
User user1 = new User("Tom", 23);
User user2 = new User("Jack", 37);
User user3 = new User("Jerry", 28);
User user4 = new User("Rose", 32);
treeMap.put(user1, 98);
treeMap.put(user2, 78);
treeMap.put(user3, 88);
treeMap.put(user4, 97);
Set set1 = treeMap.entrySet();
Iterator iterator2 = set1.iterator();
while (iterator2.hasNext()) {
Object obj = iterator2.next();
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
// User{name='Tom', age=23}--->98
// User{name='Jerry', age=28}--->88
// User{name='Rose', age=32}--->97
// User{name='Jack', age=37}--->78
}
7.6 Map 实现类之四:Hashtable
- Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的,效率低。
- Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用
- 与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value
- 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
- Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
7.7 Map 实现类之五:Properties
- Properties 类是 Hashtable 的子类,该对象用于处理属性文件
- 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key和 value 都是字符串类型
- 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);
8.Collections 工具类
Collections 是一个操作 Set、List 和 Map 等集合的工具类
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:
- 排序操作:(均为static 方法)
- reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
- 查找、替换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List 对象的所有旧值