Java基础——集合体系Map详解

上文中我们了解了集合体系中的单列集合:Java基础——集合以及Java集合——Set详解,接下来呢就让阿Q带大家一起学习一下双列集合map的使用吧。

集合体系
单列集合顶层接口 遍历方式:增强forIterator,集合转数组
Collection
	|-List 存取有序,元素可以重复,有序就有索引,有索引就可以通过索引操作元素。遍历方式:普通for,增强forIteratorListIterator,集合转数组
		|-ArrayList	不安全,效率高,数组结构:增删慢;查询快
		|-LinkedList不安全,效率高,链表结构:增删快;查询慢
		|-Vector	数组结构 安全 效率低
	|-Set 存取无序,元素唯一。遍历方式:增强forIterator,集合转数组
		|-HashSet	 哈希算法 哈希结构 存取无序 元素唯一
			|-LinkedHashSet
		|-TreeSet	二叉树算法可以排序
双列集合
Map双列集合,键唯一,值可以重复,遍历方式:根据键找值,根据键值对找键和值
	|-HashMap底层的哈希结构 保证键的唯一
		|-LinkedHashMap:存入和取出的顺序相同,同时键也是通过哈希算法保证元素唯一性的
	|-TreeMap底层的二叉树结构 保证键的排序和唯一
Map:双列集合

特点:Map双列集合,Collection是单列集合;键不可以重复,值可以重复;数据结构针对键有效。

方法:

  • 添加功能:V put(K key,V value):添加元素,如果键是第一次存储,就直接存储元素,返回null;如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值。
  • 删除功能:void clear():移除所有的键值对元素;V remove(Object key):根据键删除键值对元素,并把值返回。
  • 判断功能:boolean containsKey(Object key):判断集合是否包含指定的键;boolean containsValue(Object value):判断集合是否包含指定的值;boolean isEmpty():判断集合是否为空
  • 获取功能:Set<Map.Entry<K,V>> entrySet():获取所有的键值对的集合;V get(Object key):根据键获取值;Set keySet():获取集合中所有键的集合;Collection values():获取集合中所有值的集合
  • 长度功能:int size():返回集合中的键值对的个数

代码演示:

public static void demo1() {
    Map<String, Integer> map = new HashMap<>();
    Integer i1 = map.put("张三", 23);	//如果键是第一次存储,就直接存储元素,返回null
    Integer i2= map.put("李四", 24);
    Integer i3 = map.put("王五", 25);
    Integer i4 = map.put("赵六", 26);
    Integer i5 = map.put("张三", 26);	//相同的键不存储,值覆盖,把被覆盖的值返回

    System.out.println(map);		//{赵六=26, 张三=26, 李四=24, 王五=25}

    System.out.println(i1);			//null
    System.out.println(i2);			//null
    System.out.println(i3);			//null
    System.out.println(i4);			//null
    System.out.println(i5);			//23如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
}

public static void demo2() {
    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 23);
    map.put("李四", 24);
    map.put("王五", 25);
    map.put("赵六", 26);

	Integer value = map.remove("张三");	//根据键删除元素,返回键对应的值
	System.out.println(value);			//23
	System.out.println(map.containsKey("张三"));		//false 判断是否包含传入的键
	System.out.println(map.containsValue(100));		//false 判断是否包含传入的值			  
    System.out.println(map);				//{赵六=26, 李四=24, 王五=25}
}

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 23);
    map.put("李四", 24);
    map.put("王五", 25);
    map.put("赵六", 26);

    Collection<Integer> c = map.values();			//获取集合中所有值的集合
    System.out.println(c);					//[26, 23, 24, 25]
    System.out.println(map.size());				//4
}

遍历
方式一:通过keySet()获取所有键的集合,然后遍历键的集合,获取到每一个键,然后通过getKey()方法获取每一个值,这样把键和值一一对应的找出来了,就遍历了集合。需要用到的方法:V get(Object key):根据键获取值,
Set keySet():获取集合中所有键的集合。

代码演示:

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 23);
    map.put("李四", 24);
    map.put("王五", 25);
    map.put("赵六", 26);

    //获取所有的键
    /*
	Set<String> keySet = map.keySet();		//获取所有键的集合
	Iterator<String> it = keySet.iterator();	//获取迭代器
	while(it.hasNext()) {				//判断集合中是否有元素
		String key = it.next();			//获取每一个键
		Integer value = map.get(key);		//根据键获取值
		System.out.println(key + "=" + value);
	}
	*/

    //使用增强for循环遍历
    for(String key : map.keySet()) {		//map.keySet()是所有键的集合
        System.out.println(key + "=" + map.get(key));
    }
}

方式二:通过entrySet()获取所有的键值对的集合,然后遍历键值对的集合,获取每一个键值对,然后根据键值对来获取每一个键和值,这样把键和值一一对应的找出来了,就遍历了集合。需要用到的方法:Set<Map.Entry<K,V>> entrySet():获取所有的键值对的集合,Map.Entry接口里面的K getKey():获取键值对中的键,V getValue():获取键值对中的值。

代码演示:

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    map.put("张三", 23);
    map.put("李四", 24);
    map.put("王五", 25);
    map.put("赵六", 26);

    //Map.Entry说明Entry是Map的内部接口,将键和值的键值对封装成了Entry对象,并存储在Set集合中
    /*
	Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
	//获取每一个 键值对 对象
	Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
	while(it.hasNext()) {
		//获取每一个键值对对象
		Map.Entry<String, Integer> en = it.next();	//父类引用指向子类对象
		//Entry<String, Integer> en = it.next();	//直接获取的是子类对象
		String key = en.getKey();			//根据键值对对象获取键
		Integer value = en.getValue();			//根据键值对对象获取值
		System.out.println(key + "=" + value);
	}
	*/

    for(Entry<String, Integer> en : map.entrySet()) {
        System.out.println(en.getKey() + "=" + en.getValue());
    }
}

Map.Entry原理:Entry是Map接口里面的一个内部接口, 他的实现类是Map子类里面的一个静态的内部类

HashMap

键是如何保证唯一性的呢? 通过哈希算法。 HashSet底层就是通过HashMap的键来完成的,所以说HashMap保证键的唯一性必须要让键的元素所在的类去重写 hashCode()和 equals()方法。

代码演示:

public static void main(String[] args) {
    HashMap<Student, String> hm = new HashMap<>();
    //Student作为键,必须重写equals和hashCode() 才能让HashMap保证键的唯一
    hm.put(new Student("张三", 23), "北京");	
    hm.put(new Student("张三", 23), "上海");
    hm.put(new Student("李四", 24), "广州");
    hm.put(new Student("王五", 25), "深圳");	

    System.out.println(hm);	//{Student [name=张三, age=23]=上海, Student [name=李四, age=24]=广州, Student [name=王五, age=25]=深圳}  去掉了重复的 "张三", 23
}	
public class Student{		//重写了equals和HashCode的 Student类
    private String name;
    private int age;
    public Student() {
        super();			
    }
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    @Override
    public int hashCode() {				//重写hashCode方法
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {		//重写equals方法
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}
LinkedHashMap

存入和取出的顺序相同,同时键也是通过哈希算法保证元素唯一性的。

public static void main(String[] args) {
    LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
    lhm.put("张三", 23);
    lhm.put("李四", 24);
    lhm.put("赵六", 26);
    lhm.put("王五", 25);

    System.out.println(lhm);//{张三=23, 李四=24, 赵六=26, 王五=25}	存取有序
}
TreeMap

键是如何保证排序和唯一的呢?通过二叉树算法,TreeSet的底层就是通过TreeMap的键来完成的。

方式一:所以TreeMap保证键的唯一和排序需要让 TreeMap的键的元素所在的类去实现自然排序Comparable接口;

方式二:TreeMap保证键的唯一和排序 需要调用TreeMap的有参构造,传入一个比较器 Comparator

代码演示:

	public static void main(String[] args) {
		TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {	
            //用TreeMap的有参构造方法 传入比较器
			@Override
			public int compare(Student s1, Student s2) {
				int num = s1.getName().compareTo(s2.getName());		//按照姓名比较
				return num == 0 ? s1.getAge() - s2.getAge() : num;
			}
		});
		tm.put(new Student("张三", 23), "北京");
		tm.put(new Student("李四", 13), "上海");
		tm.put(new Student("赵六", 43), "深圳");
		tm.put(new Student("王五", 33), "广州");
		
		System.out.println(tm);
	}public static void demo1() {TreeMap<Student, String> tm = new TreeMap<>();	//用TreeMap的无参构造方法创建的对象//Student作为键,必须让Student实现Comparable接口 并且重写CompareTo方法
    	tm.put(new Student("张三", 23), "北京");	
​		tm.put(new Student("李四", 13), "上海");
​		tm.put(new Student("王五", 33), "广州");
​		tm.put(new Student("赵六", 43), "深圳");
​		
​		System.out.println(tm);}
	//Student实现了Comparable接口 重写了CompareTo方法public class Student implements Comparable<Student> {private String name;private int age;public Student() {super();}public Student(String name, int age) {super();this.name = name;this.age = age;}
​		
​		@Overridepublic int compareTo(Student o) {		// 重写了CompareTo方法int num = this.age - o.age;		//以年龄为主要条件return num == 0 ? this.name.compareTo(o.name) : num;}}
HashMap的嵌套
学校一年级学生HashMap
	键:一年级对象HashMap   值:班号1
		键:学生对象 值:归属地	
		键:学生对象 值:归属地
	键:一年级对象HashMap   值:班号2
		键:学生对象 值:归属地
		键:学生对象 值:归属地

代码演示:

public static void main(String[] args) {
    //定义一年级1班
    HashMap<Student, String> hm1 = new HashMap<>();
    hm1.put(new Student("张三", 23), "北京");
    hm1.put(new Student("李四", 24), "北京");
    hm1.put(new Student("王五", 25), "上海");
    hm1.put(new Student("赵六", 26), "广州");

    //定义一年级2班
    HashMap<Student, String> hm2 = new HashMap<>();
    hm2.put(new Student("唐僧", 1023), "北京");
    hm2.put(new Student("孙悟空",1024), "北京");
    hm2.put(new Student("猪八戒",1025), "上海");
    hm2.put(new Student("沙和尚",1026), "广州");

    //定义双元课堂
    HashMap<HashMap<Student, String>, String> hm = new HashMap<>();
    hm.put(hm1, "一年级1班");
    hm.put(hm2, "一年级2班");

    //遍历双列集合
    for(HashMap<Student, String> h : hm.keySet()) {		
        //hm.keySet()代表的是一年级所有的班级集合  h是每个班级
        String value = hm.get(h);			//get(h)根据班级对象获取班级代号value
        //遍历键的双列集合对象
        for(Student key : h.keySet()) {	//h.keySet()代表班级中所有的学生对象集合,key是每个学生
            String value2 = h.get(key);		// h.get(key) 根据学生对象找到学生的所在地value2
            System.out.println(key + "=" + value2 + "=" + value);
        }
    }

}
HashMap和Hashtable

1:HashMap线程不安全,效率高,1.2出现的;Hashtable线程安全的,效率低,1.0出现的。
2:HashMap可以存null键或null值,Hashtable不可以存储null键或null值。

代码演示:

public static void main(String[] args) {
    HashMap<String, Integer> hm = new HashMap<>();
    hm.put(null, 23);		//不报错	
    hm.put("李四", null);		//不报错
    System.out.println(hm);		//{null=23, 李四=null}

    /*
	Hashtable<String, Integer> ht = new Hashtable<>();
	ht.put(null, 23);		//编译不报错,运行报错java.lang.NullPointerException
	ht.put("张三", null);		//编译不报错,运行报错java.lang.NullPointerException
	System.out.println(ht);		
	*/
}
Collections

public static <T extends Comparable<? super T>> void sort(List list);排序:只能给List排序,而且要求被排序的List集合里面存储的元素必须实现Comparable接口(对象只有实现了Comparable接口,才能说明对象具备比较性)

public static int binarySearch(List<? extends Comparable<? super T>> list, T key);在已经排好序的list集合中查找key的索引,List集合中的元素必须实现Comparable接口

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll);给求Collection集合中最大的元素,Collection集合的元素必须实现了Comparable接口,因为如果元素不具备比较性 我如何知道谁最大呢?

public static void reverse(List<?> list);把list集合反转,list集合里面的元素没有任何要求

public static void shuffle(List<?> list);把list集合里面的元素打乱顺序,list集合里面的元素没有任何要求

代码演示:

public static void main(String[] args) {
	ArrayList<String> list = new ArrayList<>();
	list.add("a");
	list.add("c");
	list.add("d");
	list.add("g");
	list.add("f");	//String类实现了Comparable接口重写了CompareTo方法,所以可以求最大值
	//根据list集合存的元素里面的CompareTo方法的比较规则 获取集合中的最大值
    System.out.println(Collections.max(list));//g
	Collections.reverse(list);			//反转集合
	Collections.shuffle(list);			//随机置换,可以用来洗牌
	System.out.println(list);			//[g, f, d, a, c]
}

public static void demo() {
	ArrayList<String> list = new ArrayList<>();
	list.add("a");
	list.add("c");
	list.add("d");
	list.add("f");
	list.add("g");
	Collections.sort(list);	//进行二分法查找之前,必须先把list集合排序	
	System.out.println(Collections.binarySearch(list, "c"));	//1
	System.out.println(Collections.binarySearch(list, "b"));	//-2
}

好了集合的全部内容就先总结到这了,以后如果遇到什么问题再继续更新。想了解更多学习知识,请关注微信公众号“阿Q说代码”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿Q说代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值