Java集合之Map

一、概念

    在Java中,Map 是一种用于存储键值对的数据结构。它提供了一种通过键来快速查找和访问值的方式。Map 接口有多个实现类,在常用的实现类中包括 HashMap、TreeMap 和 LinkedHashMap。

Map集合的特点:

      (1)Map 是由键值对(Key-Value)组成的数据结构。每个键(Key)都是唯一的,而值(Value)可以重复 。如果键重复了,那么后面的值会替换前面的值。

      (2)Map集合中的元素,Key和Value的数据类型可以相同,也可以不同,且Map 的键和值都可以为 null。

      (3)Map里的Key和Value是一一对应的,并且Map 中的键值对没有固定的顺序。

 二、Map中的常用方法

(1)public V put(K key, V value):指定的键和值添加到Map集合中,返回值是V。
public static void main(String[] args) {
	    /* public V put (K key,V value) 返回值为:V
		 * 如果要存储的键值对,key不重复返回值V是null
		 * 如果要存储的键值对,key重复返回值V是被替换的value值
		 */
        Map<String, String> map=new HashMap<>();
        map.put("学生1","张三");
        String v=map.put("学生2","李四");
        String v1=map.put("学生1","张三");
        System.out.println(v+","+v1);
        System.out.println(map);//替换了前面的值
	}
(2) public V remove(Object key) : 把指定的键所对应的键值对元素在Map集合中删除,返回被删除的元素的值。
public static void main(String[] args) {
		/*     public V remove(Object key) 返回值:V 
		 *         如果key存在,返回被删除的值
		 *         如果key不存在,返回null
		 * */
	   Map<String,Integer> map = new HashMap<>();
	   map.put("张三",1001);
	   map.put("李四",1002);
	   map.put("王伟",1003);
	   map.put("老六",1004);
	   System.out.println(map);
	   Integer t=map.remove("王伟");
	   Integer t1=map.remove("老九");
	   System.out.println("t:"+t+",t1:"+t1);
	   System.out.println(map);
	}
(3) public V get(Object key):根据指定的键,在Map集合中获取对应的值。
public static void main(String[] args) {
		/*    public V remove (Object key):
		 *      如果key存在,返回对应的value值,如果key不存在,返回null  
		*/
		Map<Integer, String> map = new HashMap<>();
		map.put(2023,"七月");
		map.put(2024,"八月");
		map.put(2025,"九月");
		map.put(2026,"十月");
		String v1=map.get(2024);
		String v2=map.get(2021);
		System.out.println("v1:"+v1+",v2:"+v2);
	}
(4)public boolean containsKey(Object key) : 判断该集合中是否包含有此键。
public static void main(String[] args) {
		/*    boolean containsKey (Object key):
		 *      包含返回true,不包含返回false;  
		*/
		Map<Integer, String> map = new HashMap<>();
		map.put(2023,"七月");
		map.put(2024,"八月");
		map.put(2025,"九月");
		map.put(2026,"十月");
		boolean v1=map.containsKey(2023);
		boolean v2=map.containsKey(2017);
		System.out.println("v1:"+v1+",v2:"+v2);
	}
(5)public boolean containsValue(Object value): 判断该集合中是否包含有此值。(参上)
(6)public Set<K> keySet() :获取Map集合中所有的键,存储到Set集合中。
public static void main(String[] args) {

		Map<Integer, String> map = new HashMap<>();
		map.put(2023,"七月");
		map.put(2026,"八月");
		map.put(2025,"九月");
		map.put(2021,"十月");
		Set<Integer> set = map.keySet();//使用keySet()方法获取所有的键并存储到Set集合中。
		// 遍历输出所有的键
		for(Integer a : set) {
			System.out.println(a);
		}
	}
(7)public Collection<V> values() :获取Map集合中所有的值,存储到Collection集合中。
public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("2023","七月");
		map.put("2026","八月");
		map.put("2025","九月");
		map.put("2021","十月");
		// 使用 values() 方法获取所有的值并存入到Collection集合中。
		Collection<String> value=map.values();
		for(String v:value){
			System.out.println(v);
		}	
	}
(8)public Set<Map.Entry<K,V>> entrySet()  :获取到Map集合中所有的键值对,并将它们存储到一个 Set 集合中。
public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("2023","七月");
		map.put("2026","八月");
		map.put("2025","九月");
		map.put("2021","十月");
		// 使用 entrySet() 方法获取所有的键值对,存入Set集合中
		Set<Map.Entry<String, String>> entries = map.entrySet();
		for (Map.Entry<String, String> entry : entries) {
			String key = entry.getKey();
			String value = entry.getValue();
			System.out.println("K:"+key+",V:"+value);
		}
	}
(9)public static interface Map.Entry<K,V> :表示一个键值对的对象 ,可以把键值对包装成一个对象,该对象类型就是Entry类型。
public static void main(String[] args) {
		// 创建一个键值对对象
        Map.Entry<String, Integer> entry = new MyEntry<>("张三", 1001);
        // 使用 Entry 对象获取键和值
        String key = entry.getKey();
        Integer value = entry.getValue();
        // 输出键和值
        System.out.println("Key: " + key);
        System.out.println("Value: " + value);
		}
		static class MyEntry<K, V> implements Map.Entry<K, V> {
		    private K key;
		    private V value;
		    public MyEntry(K key, V value) {
		        this.key = key;
		        this.value = value;
		    }
		    @Override
		    public K getKey() {
		        return key;
		    }
		    @Override
		    public V getValue() {
		        return value;
		    }
		    @Override
		    public V setValue(V value) {
		        V oldValue = this.value;
		        this.value = value;
		        return oldValue;
		    }
	}

三、Map集合的遍历方式

(1)键找值法(键集遍历)
public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<>();
		map.put("张三",1001);
		map.put("李四",1002);
		map.put("王伟",1003);
		map.put("老六",1004);
		for(String key : map.keySet()) {
			Integer value =map.get(key);
			System.out.println("K:"+key+",V:"+value);
		}
	}
(2)键值对循环遍历
public static void main(String[] args){
		Map<String, Integer> map = new HashMap<>();
		map.put("张三",1001);
		map.put("李四",1002);
		map.put("王伟",1003);
		map.put("老六",1004);
	    Set<Map.Entry<String, Integer>> entries = map.entrySet();
	    // 使用foreach循环遍历键值对
	    for(Map.Entry<String, Integer> entry : entries) {
	    	String key = entry.getKey();
	    	Integer value = entry.getValue();
	    	System.out.println("V:"+key+",K:"+value);
	    }
	}
(3)迭代器遍历
public static void main(String[] args){
		Map<String, Integer> map = new HashMap<>();
		map.put("张三",1001);
		map.put("李四",1002);
		map.put("王伟",1003);
		map.put("老六",1004);
	    Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
	    while (iterator.hasNext()) {
	    	Map.Entry<String, Integer> entry = iterator.next();
	    	String key = entry.getKey();
	    	Integer value = entry.getValue();
	    	System.out.println("K:"+key+",V:"+value);
	    }  
	}

四、Map接口常用的实现类

(1)HashMap

  HashMap是基于哈希表实现的Map,提供快速的插入、删除和查找操作。它不保证元素的顺序,允许使用null键和null值。

4.1.1、特点:

<1>哈希表实现:HashMap内部使用哈希表数据结构,通过计算键的哈希码来确定元素在哈希表中的位置,从而实现快速的插入、删除和查找操作。平均情况下,这些操作的时间复杂度为O(1)。

<2>键值对存储:HashMap存储的数据是键值对(Key-Value)形式,每个键都是唯一的,可以用来查找对应的值。它允许使用null作为键,也允许使用null作为值。

<3>无序性:HashMap不保证元素的顺序。即使插入的顺序是固定的,遍历时得到的元素顺序也不一定相同。如果需要有序的Map,可以使用TreeMap或LinkedHashMap。\

<4>非线程安全:HashMap是非线程安全的,如果多个线程同时操作同一个HashMap对象,可能会导致不可预期的结果。如果需要在并发环境中使用Map,可以考虑使用ConcurrentHashMap。

<5>扩容与负载因子:HashMap在内部数组的填充程度达到一定比例(负载因子)后会触发扩容,以保持较低的哈希冲突率。扩容涉及到重新计算哈希码和重新分配元素存储位置,可能会导致性能略微下降。可以在创建HashMap时指定初始容量和负载因子,以适应不同的场景需求。

4.1.2、HashMap存储自定义类型键值:

HashMap存储自定义类型键值,Map集合保证key是唯一的:作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一。

class Personbest{
	private String name;
	private int age;
	public Personbest(String name, int age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Personbest [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public int 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) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Personbest other = (Personbest) 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;
	}
}
public class Test18 {
	public static void main(String[] args){
		HashMap<Personbest,String> map = new HashMap<>();
		Personbest best1 = new Personbest("张三",18);
		Personbest best2 = new Personbest("李四",20);
		Personbest best3 = new Personbest("王伟",8);
		Personbest best4 = new Personbest("老六",66);
		
		map.put(best1,"十七");
		map.put(best2,"七七");
		map.put(best3,"五五");
		map.put(best4,"四六");
		
		String v1=map.get(best4);
		String v2=map.get(best3);
		
		System.out.println(v1);
		System.out.println(v2);
		System.out.println(map);
        System.out.println(map.size());
		
	}
}

在上述示例中,Person类正确实现了hashCode()和equals()方法,允许将其作为HashMap的键。通过相同属性的键对象可以成功获取对应的值。

注意:当自定义类型的属性发生变化时,可能导致哈希码和相等性判断发生改变,如果已经将此对象作为HashMap的键使用,可能会导致无法正确地获取值。因此,在将对象用作HashMap的键之前,应尽量确保其属性不可变或不会被修改。

(2)LinkedHashMap

LinkedHashMap继承自HashMap,通过双向链表维护了元素的插入顺序或访问顺序。它保留了元素的插入顺序或访问顺序,并且支持快速插入、删除和查找操作。

特点:

<1>有序性:LinkedHashMap保持元素的插入顺序或访问顺序(可以通过构造函数参数来选择)。即使在遍历时,得到的元素顺序也是按照插入或访问的顺序。

<2>哈希表与双向链表结合:LinkedHashMap内部通过哈希表和双向链表两种数据结构相结合来实现。哈希表用于快速定位元素,双向链表用于维护元素的插入顺序或访问顺序。

<3>高效性能:LinkedHashMap对于插入、删除和查找操作具有快速的性能,平均情况下的时间复杂度为O(1)。同时,由于使用了双向链表来维护顺序,对于迭代遍历操作也能够快速地获取有序的元素。

<4>非线程安全:与HashMap一样,LinkedHashMap也是非线程安全的。如果在并发环境中需要使用LinkedHashMap,可以考虑使用ConcurrentLinkedHashMap。

<5>可指定访问顺序:LinkedHashMap提供了两种顺序模式,即插入顺序和访问顺序。在插入顺序模式下,元素的顺序按照它们被添加的顺序进行排列。在访问顺序模式下,元素的顺序会根据被访问的顺序进行调整,每次访问一个元素时,该元素会被移动到链表的尾部。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值