Map接口和Collection接口的不同 ( Collection接口 )
方式2:根据键值对对象找键和值
HashMap与Hash table的区别
Collections类和Collection的区别
Collections中的方法能线程不安全的集合变成安全的
Map接口
Map接口概述
a.将键映射到值的对象
b.一个映射不能包含重复的键
c.每个键最多只能映射到一个值
Map接口和Collection接口的不同 (Collection接口)
a.Map是双列的,Collection是单列的
b.Map的键唯一,Collection的子体系Set是唯一的
c.Map集合的数据结构值针对键有效,跟值无关 Collection集合的数据结构是针对元素有效
Map接口成员方法
添加功能
V put(K key,V value) 将指定的值与该映射中的指定键相关联
import java.util.HashMap; import java.util.Map; public class MapTest1 { public static void main(String[] args) { //Map是一个接口,不能实例化,借助子类HashMap来实例化 Map<String, String> map = new HashMap<>(); //V put(K key,V value) 将指定的值与该映射中的指定键相关联 map.put("充电器","手机"); map.put("电脑","鼠标"); System.out.println(map.put("电脑","键盘")); //如果插入的键一样,值会被覆盖,返回的是被覆盖的值 System.out.println(map); } }
删除功能
V remove(Object key) 如果存在(从可选操作),从该Map中删除一个键的映射
map.remove("电脑");
void clear() 从该Map中删除所有的映射(可选操纵)
map.clear();
判断功能
boolean containsKey(Object key)如果此映射包含指定键的映射,则返回true
//boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回true System.out.println(map); System.out.println(map.containsKey("充电器"));
boolean containsValue(Object value) 如果此Map将一个或多个键映射到指定的值,则返回true。
map.containsValue("手机")
boolean isEmpty()如果此Map不包含键值映射,则返回true
map.isEmpty();//判断是否有键值对,有返回true,无false
获取功能
V get(Object key) 返回指定键所映射的值,或null如果此映射包含该键的映射
System.out.println(map.get("充电器"));
Set<K> keySet() 返回此Map中包含的键的Set试图
Set<String> set=map.keySet(); //遍历 for (String s:set){ System.out.println(s); }
Collection<V> values()返回此Map中包含的值的Collection视图
//Collection<V> values() 返回此Map中包含的值的Collection视图 Collection<String> value =map.values(); for (String s :value){ System.out.println(s); }
Set<Map.Entry<K,V>> entrySet()获取Map中所有的元素,元素的类组成是由一个键和一个值组成
//Set<Map.Entry<K,V>> entrySet() 获取Map中所有的元素,元素的类组成是由一个键和一个值组成 Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String, String> s :entries){ System.out.println(s); }
长度功能
int size() 返回此Map中键值映射的数量
int size = map.size(); System.out.println(size); //结果为2,取决于里面有多少个键值对
Map集合遍历
方式1:根据键找值
获取所有键的集合
遍历键的集合,获取到每一个键
根据键找值
例:
import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapTest2 { public static void main(String[] args) { //创建集合对象 Map<Integer, String> map = new HashMap<>(); //向集合添加元素 map.put(11,"qew"); map.put(23,"qew"); map.put(33,"sfs"); map.put(22,"asf"); //遍历 Set<Integer> set = map.keySet(); //获取到每一个键 for (Integer s:set){ String s1 = map.get(s); //获取到每一个键对应的值 System.out.println(s+":"+s1); } } }
方式2:根据键值对对象找键和值
获取所有键值对对象的集合
遍历键值对对象的集合,获取到每一个键值对对象
根据键值对对象找键和值
//创建集合对象 Map<Integer, String> map = new HashMap<>(); //向集合添加元素 map.put(4,"rte"); map.put(23,"d234"); map.put(5,"e121"); map.put(75,"qee"); map.put(22,"fa"); //遍历 Set<Map.Entry<Integer, String>> entries = map.entrySet(); //获取到键值对集合 for (Map.Entry<Integer, String> s:entries){ Integer key = s.getKey(); //获取到键值对对应的键 String value = s.getValue(); //获取到键值对对应的值 System.out.println(key+":"+value); }
HashMap类
HashMap类概述
键是哈希表结构,可以保证键的唯一性
HashMap案例
HashMap<String,String>
HashMap<Integer,String>
上面两个跟Map集合中的案例一样,重点说下面的
HashMap<String,Student>
首先封装一个学生类
public class Student { private String name; private int age; public Student() {} public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
在创建集合添加学生对象测试
import java.util.HashMap; import java.util.Map; import java.util.Set; public class HashMapTest1 { public static void main(String[] args) { //创建集合对象 HashMap<String, Student> hashMap = new HashMap<>(); //创建学生对象 Student s1 =new Student("student1",23); Student s2 =new Student("student2",14); Student s3 =new Student("student3",17); Student s4 =new Student("student4",25); Student s5 =new Student("student5",23); //向集合添加元素 hashMap.put("sas",s1); hashMap.put("qwe",s2); hashMap.put("fsa",s3); hashMap.put("ddd",s4); hashMap.put("qca",s5); //遍历 Set<Map.Entry<String, Student>> entries = hashMap.entrySet(); for (Map.Entry<String, Student> s:entries){ String key = s.getKey(); Student value = s.getValue(); //也可以调用student中的get方法把名字,年龄获取出来遍历 System.out.println(key+":"+value); } } }
HashMap<Student,String>
import java.util.HashMap; import java.util.Map; import java.util.Set; public class HashMapTest2 { public static void main(String[] args) { //创建集合对象 HashMap<Student, String> hashMap = new HashMap<>(); //创建学生对象 Student s1=new Student("qa",23); Student s2=new Student("ea",25); Student s3=new Student("fa",22); Student s4=new Student("da",15); Student s5=new Student("qa",23); //向集合添加元素 hashMap.put(s1,"111"); hashMap.put(s2,"222"); hashMap.put(s3,"333"); hashMap.put(s4,"444"); hashMap.put(s5,"555"); //遍历 Set<Map.Entry<Student, String>> entries = hashMap.entrySet(); for (Map.Entry<Student, String> s:entries){ Student key = s.getKey(); String value = s.getValue(); System.out.println(key+":"+value); } } }
从输出结果能发现,key有重复的对象,这违背了map中键是唯一的定义,原因是添加元素的put方法的源码涉及到hashCode()方法和equals()方法来判断元素是否重复(在Hash Set类中说过,Set接口),而我们创建做为key的自定义Student类中没有重写hashCode()方法和equals()方法,所以只能调用Object类中的equals方法来比较地址值,每一个学生对象都是new出来的,地址值固然不一样。
解决方法:在Student类中重写hashCode()方法和equals()方法
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(name, age); }
这样key就不会重复了
LinkedHashMap类
LinkedHashMap类概述
a.继承自HashMap类,实现了Map接口
b.Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。
哈希表保证元素的唯一,保证key是唯一
链表保证有序 (存储和取出的顺序一致)
例:
import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; public class LinkedHashMapTest1 { public static void main(String[] args) { //创建集合对象 LinkedHashMap<String, String> map = new LinkedHashMap<>(); //向集合添加元素 map.put("s1","qqw"); map.put("s2","q232"); map.put("s3","q211"); map.put("s4","d23"); map.put("s1","dsa"); //遍历 Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String, String> s:entries){ String key = s.getKey(); String value = s.getValue(); System.out.println(key+":"+value); } } }
从结果可以看出重复的key的值被覆盖了,并且输出的顺序就是存放的顺序
TreeMap类
TreeMap类概述
键是红黑树结构,可以保证键的排序和唯一性
TreeMap案例
HashMap<String,String>
import java.util.Map; import java.util.Set; import java.util.TreeMap; public class TreeMapTest1 { public static void main(String[] args) { //创建集合对象 TreeMap<String, String> map = new TreeMap<>(); //向集合添加元素 map.put("HashSet","Set接口"); map.put("TreeSet","Set接口"); map.put("LinkedHashSet","Set接口"); map.put("HashMap","Map接口"); map.put("HashMap","Map接口"); //遍历 Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String, String> s:entries){ String key = s.getKey(); String value = s.getValue(); System.out.println(key+":"+value); } } }
可以看出结果去重了,而且按key中的首字母排序,因为无参构造走的是自然排序,String类实现了Comparable接口,重写了ComparaTo方法( TreeSet类中有说过),String中ComparaTo方法比较ASCII码值,所以按首字母排序。
HashMap<Student,String>
方法一:
首先封装一个学生类2,跟学生类1一样的(不加hashCode方法和equals方法)
再创建集合
import java.util.Map; import java.util.Set; import java.util.TreeMap; public class TreeMapTest2 { public static void main(String[] args) { //创建集合对象 TreeMap<Student2, String> map = new TreeMap<>(); //创建学生对象 Student2 s1 =new Student2("student1",23); Student2 s2 =new Student2("student2",22); Student2 s3 =new Student2("student3",23); Student2 s4 =new Student2("student1",23); Student2 s5 =new Student2("student4",20); //向集合添加元素 map.put(s1,"q111"); map.put(s2,"w111"); map.put(s3,"e111"); map.put(s4,"q111"); map.put(s5,"t111"); //遍历 Set<Map.Entry<Student2, String>> entries = map.entrySet(); for (Map.Entry<Student2, String> s:entries){ Student2 key = s.getKey(); String value = s.getValue(); System.out.println(key+":"+value); } } }
然后到这一步你会报错,因为这里走的还是无参构造,自然排序,所创建的Stuent2类没有实现Comparable接口,而自然排序这个接口中有一个向下转型,所以会类型转换异常报错(具体跟TreeSet类中一 样Set接口)
解决方法:创建的Student2类需实现Comparable接口,并重写接口的ComparaTo方法,在其中自定义排序方法
public class Student2 implements Comparable<Student2> { private String name; private int age; public Student2() { } public Student2(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Student2 o) { //比较年龄是否一样 int i1=o.age-this.age; //年龄一样,姓名不一定一样 int i2= i1==0 ? o.name.compareTo(this.name):i1; return i2; } }
可以看出结果去重且按自定义方法排序(按年龄)
方法二:
当然,如果你不想改动学生类,那就走有参构造方法,也就是比较器排序
此时学生类是最初的封装状态,不需要修改,只需要在创建对象时修改就可以了,这里采用 匿名内部类的方式,直接在创建对象时实现Comparato接口。
//创建集合对象 TreeMap<Student2, String> map = new TreeMap<>(new Comparator<Student2>() { //匿名内部类 @Override public int compare(Student2 o1, Student2 o2) { //比较年龄是否一样 int i1 = o1.getAge() - o2.getAge(); //年龄一样,姓名不一定一样 int i2 = i1 == 0 ? o1.getName().compareTo(o2.getName()) : i1; return i2; } });
Map集合练习案例
例1:"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
import java.util.Map; import java.util.Set; import java.util.TreeMap; public class MapTest4 { public static void main(String[] args) { //创建字符串对象 String s="aababcabcdabcde"; //创建集合对象 TreeMap<Character, Integer> map = new TreeMap<>(); char[] chars = s.toCharArray(); //转成字符数组 //遍历字符数组 for (Character c : chars) { Integer integer = map.get(c); //用每一个字符当作键去找值 if (integer == null) { //如果输出值为null,表示集合中没有这个键,添加这个键并赋值1; map.put(c, 1); } else { //如果输出不为null,表示集合中有这个键,赋值返回的值value+1,返回覆盖到集合中 integer++; map.put(c, integer); } } //遍历集合 Set<Map.Entry<Character, Integer>> entries = map.entrySet(); for (Map.Entry<Character, Integer> e:entries){ Character key = e.getKey(); Integer value = e.getValue(); System.out.print(key+"("+value+")"); } } }
例2:ArrayList集合嵌套HashMap集合
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapTest5 { public static void main(String[] args) { //创建ArrayList集合对象 ArrayList<HashMap<String, String>> list = new ArrayList<>(); //创建2个HashMap集合,并添加元素 HashMap<String, String> map1 = new HashMap<>(); map1.put("user1","qwq"); map1.put("user2","q33q"); HashMap<String, String> map2 = new HashMap<>(); map2.put("user3","q3we"); map2.put("user4","aa"); //把HashMap集合添加进入ArrayList集合 list.add(map1); list.add(map2); //遍历ArrayList集合 for (HashMap<String, String> s:list){ //遍历HashMap集合 Set<Map.Entry<String, String>> entries = s.entrySet(); for (Map.Entry<String, String> m:entries){ String key = m.getKey(); String value = m.getValue(); System.out.println(key+":"+value); } } } }
HashMap与Hash table的区别
a.Hash Map和Hash table它们存储的都是一个个的键值对
b.Hash Map中允许key,value为null,而Hash table不允许
c.Hashtable是线程安全的,HashMap是不安全的
Collections类
Collections类概述
针对集合操作 的工具类
Collections类和Collection的区别
a.Collection是单列集合的顶层接口,有两大子类接口:List接口和Set接口
b.Collections是一个针对于集合操作的工具类,可以对集合进行排序,还有查找(二分查找)
Collections成员方法
public static <T> void sort(List<T> list)集合排序
import java.util.ArrayList; import java.util.Collections; public class CollectionsTest1 { public static void main(String[] args) { //创建集合对象 ArrayList<Integer> list = new ArrayList<>(); //向集合添加元素 list.add(54); list.add(23); list.add(123); list.add(42); list.add(32); list.add(24); //public static <T> void sort(List<T> list) 排序 System.out.println("原集合:"+list); Collections.sort(list); System.out.println("排序后:"+list); } }
public static <T> int binarySearch(List<?> list,T key)二分查找,返回索引
System.out.println("原集合:"+list); int i = Collections.binarySearch(list, 123); System.out.println(i);
public static <T> T max(Collection<?> coll) 集合中最大值
Integer max = Collections.max(list); System.out.println(max); //123
public static void reverse(List<?> list)反转
System.out.println("原集合:"+list); Collections.reverse(list); System.out.println("反转后:"+list);
public static void shuffle(List<?> list) 随机置换(随机排序)
System.out.println("原集合:"+list); Collections.shuffle(list); System.out.println("随机置换后:"+list);
Collections中的方法能线程不安全的集合变成安全的
例: static List synchronizedList(List list) (还有很多,不一一举例了)
返回由指定列表支持的同步(线程安全)列表。
List<Integer> list1 = Collections.synchronizedList(list); System.out.println(list); System.out.println(list1);
可以看出两个list和list1是一样的,Collections只是给list套了一层,让它变成安全的,在Vector类中说过虽然Vector是安全的,但Collections工具类比它更好。