【第18天】Java集合(五)---Map接口概述及Map接口实现的HashMap类、SortedMap接口实现的TreeMap类

版权声明:©2018 本文為博主來秋原創,轉載請註明出處,博主保留追責權利。 https://blog.csdn.net/qq_30257081/article/details/84590196

1 Map的通性

在这里插入图片描述

       一种键值对类型的集合,每次向集合添加一对元素,添加“主键Key=值Value”。其中只能在新建时传入且唯一,传入后不得修改;值不唯一,可直接修改。

1.1 基本用法与特点

  • 创建Map对象

     HashMap<主键类型,值类型> map = new HashMap<>();
     TreeMap<主键类型,值类型> map = new TreeMap<>();
    
  • 添加元素

     map.put(主键,值);
     map1.putAll(map2);
    
  • 得到集合的大小

     map.size();
    
  • 根据主键得到值对象

     map.get(主键); -> 值
    
  • 判断集合里是否出现指定的主键对象

     map.containsKey(主键);
    
  • 判断集合里是否出现指定的值对象

     map.containsValue(值);
    
  • 根据主键删除元素

     map.remove(主键);
    
  • 若想快速判断Map中某个键/值是否存在,要善用contains()方法。根据类中定义好的equals()方法,查看是否存在,可以直接返回boolean值。同样使用remove(主键)时,也可以通过equals()方法定制删除主键的规则。

1.2 遍历

姓名 得分
  • 通过Map集合得到所有的主键对象(主键对象是唯一且无序的,故使用Set来接收即可)能获取到的是:
姓名
	Set<主键> set = map.keySet();

得到主键的同时,主键是唯一的,可以根据主键得到值对象:map.get(主键),只能根据主键得到对应的值对象而不能改。

  • 通过Map集合得到所有的值对象 (主键对象是不唯一且无序的,故只能使用Collection来接收),能获取到的是:
得分
	Collection<值> coll = map.values();

无法根据值得到对应的主键,因为值是不唯一的,只能将值取出。

  • 通过Map集合得到所有记录的主键和值且可以对值进行修改

      Set<Map.Entry<主键,值>> set = map.entrySet();
      对set遍历可以获取到每一条记录的主键和值
      通过记录得到主键对象:记录.getKey()
      通过记录得到值对象:记录.getValue()
      通过记录修改值对象:记录.setValue(XXX)
    

能获取到的是一条一条的:

姓名 得分
//将Eric的成绩 + 20分
import java.util.*;
public class Test{
	public static void main(String[] args){
		HashMap<String,Integer> map = new HashMap<>();
		//添加元素:
		map.put("Allen",455);
		map.put("Eric",122);
		map.put("Cindy",600);
		
		//通过Map集合得到一条记录 -> [主键,值]
		Set<Map.Entry<String,Integer>> set = map.entrySet();
		
		//通过对集合每一条记录遍历,得到x -> 即集合里面的每一条记录
		for(Map.Entry<String,Integer> x : set){
			
			//通过记录得到主键对象
			String name = x.getKey();
			//通过记录得到值对象
			Integer score = x.getValue();
			
			if(name.equals("Eric")){
				x.setValue(score + 20);
			}
		}
		System.out.println(set);//--->[Cindy=122, Allen=455, Eric=620]
		System.out.println(map);//--->[Cindy=122, Allen=455, Eric=620]
	}
}
  • 因Map是一个键值对,当单独取值key或value时,不要对其进行修改,只作为一个遍历查找的简便方法。对单独取值得到的集合进行add()操作会报UnsupportOperationException。但可以对Set类型的主键集合中元素进行删除,进而Map中整个元素被删除,因为其具有唯一性。

  • 主键不能直接修改,若修改需要先remove(主键)之前的,再put(主键,值)进新的键值对。

  • 值可以修改,使用setValue()直接使用put(旧主键,新值)进行覆盖

  • 在使用迭代器或foreach进行遍历时注意CME异常,要使用迭代器的remove方法,增加新元素时需要使用新集合接收,在循环外将新集合加入旧集合。

2 HashMap集合的特性

  • Map接口的实现类,方法与Map的通用方法相同,但底层需遵循之前学过的hashCode()、==、equals()的比较机制。
  • HashMap的特性与HashSet的其他特性也类似,比如在对集合中元素修改时,不能对已传入的元素的与哈希特征值生成有关的属性进行直接修改。
import java.util.*;
public class Test{
	public static void main(String[] args){

		HashMap<Student,Integer> map = new HashMap<>();

		Student s1 = new Student("张三", 18);
		Student s2 = new Student("李四", 22);
		Student s3 = new Student("王五", 26);
		Student s4 = new Student("zz", 25);

		map.put(s1,77);
		map.put(s2,88);
		System.out.println(map.containsKey(s4));//--->true
		//因Student对象的hashCode()和equals()都一样
		//张三、李四被视为相等对象,新加入的李四对象不会加入集合,但年龄所对应的Integer类hashCode()值有不同,故可以加入集合
		//同理可以考虑主键名不变,修改value值可以put(旧主键名, 新值)直接覆盖
		//传入的主键相同,但主键是唯一的,所以不再添加新的,但value值不同,故可以添加
		System.out.println(map);//--->{张三=88} 
		map.remove(s3);
		System.out.println(map);//--->{}
	}
}

class Student{
	String name;
	int age;

	public Student(String name,int age){
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString(){
		return name;
	}

	@Override
	public boolean equals(Object obj){
		return true;//任何两个对象都视为相等对象
	}

	@Override
	public int hashCode(){
		return 1;//任何对象的哈希码值都是1
	}
}

  • HashMap和Hashtable之间的区别(Hasntable为最早的Map集合形式)

    • 同步特性
      Hashtable同一时时间允许一个线程进行访问,效率较低,但是不会出现并发错误
      HashMap同一时间允许多个线程进行访问,效率较高,但是可能会出现并发错误

      JDK5.0开始集合的工具类(Collections)里面提供一个方法(synchroniedMap()) 可以将线程不安全的HashMap变成线程安全的集合对象,所以Hashtable被淘汰。但添加了synchronizedMap()之后的HashMap与HashTable无异,都是在分组前上锁来控制传入的数据,这时只能逐个进入分组;
      JDK5.0后不如使用util包下concurrent子包中的ConcurrentHashMap集合,对每个小组加锁,允许进入多个数据,效率更高。

    • 对null容忍度不同
      HashMap无论是主键还是值对象,都可以存放null。由于主键是唯一,所以主键只能存放一个null,Hashtable无论是主键还是值对象,都不能存放null,否则都会空指针异常。

    • 底层分组不同
      HashMap默认分16个小组,程序员可以按照自己的意愿随意的进行指定分组组数,但是最终一定是2的n次方数,比如定义为17组,最后系统会自动开辟32组。
      Hashtable默认分11个小组,程序员可以按照自己的意愿随意指定分组组数。

    • 出现的版本不同
      Hashtable适用于JDK1.0及以后,
      HashMap适用于JDK1.2及以后。

3 TreeMap集合的特性

  • SortedMap接口的实现类,方法与Map的通用方法相同,但底层需遵循之前学过的compareTo()/compare的比较机制。
  • TreeMap的特性与TreeSet的其他特性也类似,比如在对集合中元素修改时,不能对已传入的元素的与compareTo()/compare有关的属性进行直接修改。
import java.util.*;
public class Test{
	public static void main(String[] args){

		TreeMap<Student,Integer> map = new TreeMap<>();

		Student s1 = new Student("张三",18);

		map.put(s1,77);

		//compareTo()一直向右比较,因返回值无法返回0而不会停止比较,所以remove()方法无法匹配并返回值
		map.remove(s1);
		System.out.println(map);//--->{张三=77}

		//compareTo()一直向右比较,因返回值无法返回0而不会停止比较,所以containsKey()方法无法匹配并返回值
		System.out.println(map.containsKey(s1));//--->false

		//compareTo()一直向右比较,因返回值无法返回0而不会停止比较,所以get()方法无法匹配并返回值
		System.out.println(map.get(s1));//--->null

		System.out.println(map.size());//--->1
		map.put(s1,77);
		
		//因compareTo()返回值为1可以无限向右子树添加相同的元素
		System.out.println(map.size());//--->2

	}
}

class Student implements Comparable<Student>{
	String name;
	int age;

	public Student(String name,int age){
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString(){
		return name;
	}

	@Override
	public int compareTo(Student stu){
		return 1;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_30257081/article/details/84590196