Set&Map集合

JAVA学习笔记之Map&Set

1.HashSet集合

1.1Set接口的特点

1.无序:存入集合的顺序与取出集合的顺序不一致
2.没有索引
3.元素唯一:存入集合的元素没有重复

1.2案例

  //创建set集合对象
        Set<String > set = new HashSet<String>();
        //添加数据
        set.add("java");
        set.add("php");
        set.add("python");
        //遍历集合对象
        /**
         * set对象可以通过三张方法遍历集合
         * 转数组
         * 迭代器
         * 增强for循环
         */
        //转数组:
        Object[] objects = set.toArray();
        for (int i = 0; i < objects.length ; i++) {
            System.out.println(objects[i]);
        }
        System.out.println("======================");
        //迭代器
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }
        System.out.println("======================");
        //增强for
        for(String s :set){
            System.out.println(s);
        }

1.3Set集合的唯一性原理

查看HashSet对象的add方法,发现是调用map.put方法,再往上查看,找到putVal方法

//K key:要添加的元素		
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)//table是前文定义的不被序列化的节点,如果为空或者长度为0,调用resize()方法重新分配表
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
		//会首先比较Hash值(每个元素都会调用hashcode()产生一个哈希值)
		//如果新添加的元素与集合中已有的元素的哈希值都不同,那新的元素存入集合
		//如果新添加的元素与集合中已有的某个元素哈希值相同,此时还需要调用equals方法比较地址
		//如果方法返回true,说明新添加的元素与集合中的某个元素属性相同,则新元素不加入到集合
		//如果返回false,说明新添加的元素与集合中所有的元素属性都不同,新元素加入到集合中
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;//相同,则退出循环
                p = e;
            }
        }
        if (e != null) { 
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
	 
    afterNodeInsertion(evict);
    return null;
}

1.4HashSet存储自定义对象

我们自定义对象,并将它存储到set集合中,会发现重复的对象可以写进同一个集合,那如何解决这个问题呢?前面提到过,set集合具有成员唯一性,存入元素不能重复,java中检查元素是否重复是通过检查哈希值与地址值,所以,我们可以通过重写equals()方法和hashcode()方法来解决这个问题:

主要是通过重写equals(Object obj)方法和hashCode方法

public class Student {
	    private String name;
	    private Integer age;
	
	    public String getName() {
	        return name;
	    }
	
	    public void setName(String name) {
	        this.name = name;
	    }
	
	    public Integer getAge() {
	        return age;
	    }
	
	    public void setAge(Integer age) {
	        this.age = age;
	    }
	
	    public Student() {
	    }
	
	    public Student(String name, Integer age) {
	        this.name = name;
	        this.age = age;
	    }
	
	    @Override
	    public boolean equals(Object o) {
			//优化:提高效率
			if(this == o){
				return true;
			}
			//提高健壮性
			if(this.getClass() != o.getClass()){
				return false;
			}
	        Student student = (Student)o;//向下转型,可可以获取子类的对象成员
	        //比较年龄是否相等,如果不等则返回false
	        if (!this.age.equals(student.age)){
	            return false;
	        }
	        //比较姓名是否相等,如果不等则返回false
	        if (!this.name.equals(student.name)){
	            return false;
	        }
	        //默认返回true,说明两个学生是相等的
	        return true;
	    }
	
	    @Override
	    public int hashCode() {
	        return Objects.hash(name, age);
	    }
	}

可以使用集成开发工具如Eclipse,Intellij IDEA中提供的equals()与hashcode()重写方法

1.5 Collections工具类

Collection和Collections有什么区别?

Collection是集合体系的最顶层,包含了集合体系的共性

Collections是一个工具类,方法都是用于操作Collection

Collections中常用方法

	static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
	static void  sort(List<T> list) :按照列表中元素的自然顺序进行排序
	static void shuffle(List list):随机置换  
	static void reverse(List list)  :反转
	static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
	static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
		注意:目标列表的长度至少等于源列表的长度
	static int  binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 

注意

Collections的方法中,返回值大多是void,说明这个对象,本身发生了变化,如果返回了新的对象,说明本身可能没有变化,有一个的特殊类StringBuffer的append方法,不会创建新的对象。

  • 例如static void shuffle(List list)随机置换方法,返回值void,说明随机置换了list对象,如果返回值是新的对象如List list1对象,说明传递过来的list对象没有发生变化,置换的是返回值list1对象

2.HashMap集合

2.1Map和Collection的区别

	Map:是一个双列集合,元素是成对存在的,通常用于处理有对应关系的数据,键是不可以重复的,但是值是可以重复的,每个键只能对应一个值
	Collection:是一个单列集合,元素是孤立存在的,向集合中存储元素采用一个个元素的方式存储

2.2Map的常用功能

映射功能

  • V put(K key,V value):将key映射到value功能,如果key存在,则覆盖value,返回原value值,如果key不存在,则返回null

获取功能

  • V get(Object Key):返回指定key所对应的value
  • Set keySet():获取所有的key
  • Collection values:获取所有的value
  • int size():返回对应关系的个数

判断功能

  • boolean containsKey(Object Key):判断指定的key是否存在
  • boolean containsValue(Object Value):判断指定的value是否存在
  • boolean isEmpty():判断是否有对应关系

删除功能

  • void clear():清除所有的对应关系
  • V remove(Object Key):根据指定的key删除对应关系,并返回key所对应的值。如果没有删除成功,则返回null

遍历功能

  • Set<Map.Entry<K,V>> entrySet():Map的第二种遍历方法,通过面向对象

2.3案例

public class MapDemo {
		    public static void main(String[] args) {
		        Map<String ,String > map = new HashMap<>();
		        //添加功能 V put(K key,V value) :将key映射到value功能,如果key存在,则覆盖value,返回原value值,如果key不存在,则返回null
		        map.put("001","小一");
		        map.put("002","小二");
		        map.put("003","小三");//返回null
		        map.put("001","小四");//key值存在,会返回原value值“小一”,并覆盖value,现在key "001"对应的是"小四"。判断是否重复,参加上方set集合的add方法
		        //判断功能:boolean containsKey(Object Key):判断指定的key是否存在
		        System.out.println(map.containsKey("001"));//返回true
		        //判断功能:boolean containsValue(Object Value):判断指定的value是否存在
		        System.out.println(map.containsValue("小一"));//返回false,小一已经被小四取代了
		        //判断功能:boolean isEmpty():判断是否有对应关系
		        System.out.println(map.isEmpty());
		        //删除功能:void clear():清除所有的对应关系
		        map.clear();
		        //删除功能: V remove(Object Key):根据指定的key删除对应关系,并返回key所对应的值。如果没有删除成功,则返回null
		        map.put("001","小一");
		        map.put("002","小二");
		        map.put("003","小三");
		        System.out.println(map.remove("001"));
		        //获取功能:int size():返回对应关系的个数
		        System.out.println(map.size());
		        //获取功能: V get(Object Key):返回指定key所对应的value
		        System.out.println(map.get("003"));
		        //获取功能:Set<K> keySet():获取所有的key
		        Set<String> set = map.keySet();//返回值是Set类型:是因为map集合中key是唯一不可重复的,而set类型具有元素的唯一性
		        for (String key :set){
		            System.out.println(key);
		        }
		        //获取功能:Collection<V> values:获取所有的value
		        Collection<String> collection = map.values();//返回值是Collection类型:是因为map集合中value值是允许重复的,如果返回set,重复的值就不存在了,而collection是允许重复的。注意:不是list类型
		        for(String value:collection){
		            System.out.println(value);
		        }
		        //Map的第一种遍历方式:获取所有的key,遍历key,通过key找到map中的value
		        Set<String> keys = map.keySet();
		        for (String key :keys){
		            System.out.println(map.get(key));
		        }
		        //遍历功能:Set<Map.Entry<K,V>> entrySet():Map的第二种遍历方法,通过面向对象
		        Set<Map.Entry<String ,String>> entrys=map.entrySet();
		        for (Map.Entry<String ,String> entry:entrys){
		            String key = entry.getKey();
		            String value = entry.getValue();
		            System.out.println("key:"+key+"value:"+value);
		        }
		        /**原理
		         * class Entry<K,V>{
		         *      K key;
		         *      V value;
		         *      public Entry(K key,V value){
		         *          this.key = key;
		         *          this.value = value;
		         *       }
		         *
		         *      public K getKey(){
		         *          return key;
		         *      }
		         *
		         *      public V getValue(){
		         *          return value;
		         *       }
		         * }
		         */
		    }
		}

今日小结

  • 今天主要重新回顾了Set集合与Map集合,真的,每回顾一次,就发现自己了解的并不多。以前顶多是可以熟练运用,今天算是可以勉强理解其中的一点原理。当然还不够,底层的添加方法还使用了二叉树的相关知识,这是我的盲点,恩,记下来,这也是需要攻克的。今天就到这里吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ruozhuliufeng

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

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

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

打赏作者

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

抵扣说明:

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

余额充值