一、Set

1.1 Set集合简介

Set接口也继承自Collection接口,同时也继承了Collection接口的全部方法。它有如下特点:
1、Set集合不允许存放重复元素,所以在向Set集合中添加元素,我们需要针对元素进行重写equals()
2、Set集合在存放元素时,可以是有序的,也可以是无序的(具体要根据使用的子类的类型来定义)
3、无法使用 下标 的方式来进行检索元素

Set接口的具体子类

实现Set接口的类包括AbstractSet、ConcurrentSkipListSet、CopyOnWriteArraySet、EnumSet、HashSet、JobStateReasons、LinkedHashSet、TreeSet,但是最常用的是HashSetTreeSet

1.2 HashSets

HashSet 类是基于哈希算法的Set接口实现,结构为数组+链表+红黑树

1.2.1 HashSet集合的特点

1、Hashset 是无序的
2、它可以通过比较hash值,以及比较equals() 来判断,集合中是否已经存在 相同的元素,如果有,就不需要再进行存放
3、它允许包含null元素

1.2.2 HashSet的使用和底层细节

无标题.png

  1. Set<String> data = new Hash<String>();

但是new 该集合的时候,内部实际上用到了HashMap,并采用HashMap的key去重方案,完成对集合中元素的去重

1.2.3 HashSet的常用API

  1. package com.woniuxy.java21.study;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. public class HashSetStudy {
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. study01();
  8. }
  9. /**
  10. *
  11. * HashSet的基本用法
  12. */
  13. private static void study01() {
  14. // TODO Auto-generated method stub
  15. Set<String> data = new HashSet<String>();
  16. //添加元素
  17. data.add("a");
  18. data.add("a");
  19. data.add("a");
  20. data.add("b");
  21. data.add("c");
  22. //获得集合中元素的个数
  23. System.out.println(data.size());
  24. //判断集合中是否拥有某一个元素
  25. System.out.println(data.contains("b"));
  26. //遍历(1) foreach
  27. // for (String string : data) {
  28. // System.out.println(string);
  29. // }
  30. //遍历(2)迭代器
  31. // Iterator iterator = data.iterator();
  32. // while(iterator.hasNext()) {
  33. // String str = (String) iterator.next();
  34. // System.out.println(str);
  35. // if("a".equals(str)) {
  36. // //移除元素的方法
  37. // iterator.remove();
  38. // }
  39. // }
  40. data.remove("a");
  41. System.out.println(data.size());
  42. }
  43. }

1.3 TreeSet

TreeSet同样实现了Set接口,例外还实现SortedSet接口,从而实现了:既可以去重,又可以排序,结构为:红黑树

1.3.1 TreeSet的特点:

1、它内部的元素在存放时,有一定的存储顺序
2、它同样不能存放重复元素
3、无法存放null元素

1.3.2 TreeSet的用法和常用API

  1. package com.woniuxy.java21.study;
  2. import java.util.Iterator;
  3. import java.util.Set;
  4. import java.util.TreeSet;
  5. public class TreeSetStudy {
  6. public static void main(String[] args) {
  7. // TODO Auto-generated method stub
  8. //定义TreeSet的集合
  9. TreeSet<String> data = new TreeSet<String>();
  10. data.add("a");
  11. data.add("c");
  12. data.add("a");
  13. data.add("d");
  14. data.add("b");
  15. //得到集合长度
  16. System.out.println(data.size());
  17. //判断集合中是否包含某一个元素
  18. System.out.println(data.contains("a"));
  19. //判断集合是否为空
  20. System.out.println(data.isEmpty());
  21. // data.remove("a");
  22. //取得第1个元素
  23. System.out.println(data.first());
  24. //取得最后1个元素
  25. System.out.println(data.last());
  26. //严格返回比“b” 大的,该集合中的最小元素,如果没有此元素则返回 null (比我大的,但是又是最靠近我的)
  27. System.out.println(data.higher("b"));
  28. //返回比我小的,也是最靠近我的
  29. System.out.println(data.lower("b"));
  30. //取得集合中,比我小的所有元素
  31. System.out.println(data.headSet("c"));
  32. //取得集合中,比我大的所有元素(但是包含自己)
  33. System.out.println(data.tailSet("b"));
  34. //遍历(1)foreach
  35. // for (String string : data) {
  36. // System.out.println(string);
  37. // }
  38. //遍历(2)迭代器
  39. // Iterator<String> iterator = data.iterator();
  40. // while(iterator.hasNext()) {
  41. //
  42. // String str = iterator.next();
  43. //
  44. // System.out.println(str);
  45. // }
  46. }
  47. }

1.3.3 TreeSet的排序规则

集合中一般有2种排序规则:自然排序,自定义排序

自然排序

在JDK类库中,有一部分类实现了Comparable接口,例如Integer、Double、String等等。Comparable接口在java.lang包中,该接口有一个compareTo(Object o)方法,返回整型数据。对于表达式x.compareTo(y),如果返回值为0,则表示x和y相等;如果返回值大于0,则表示x大于y;如果返回值小于0,则表示x小于y。TreeSet集合调用对象的compareTo()方法比较集合中的大小,然后进行升序排列,这种方式称为自然排序
如果元素要参与自然排序,需要实现一个接口Comparable
白话:凡是元素自带了排序规则的,都是属于自然排序
eg:无标题.png
无标题.png

  1. package com.woniuxy.java21.bean;
  2. import java.io.Serializable;
  3. public class StudentBean implements Serializable,Comparable<StudentBean> {
  4. /**
  5. *
  6. */
  7. private static final long serialVersionUID = -2640219895840760729L;
  8. private String name;
  9. private int age;
  10. public StudentBean(String name, int age) {
  11. super();
  12. this.name = name;
  13. this.age = age;
  14. }
  15. public StudentBean() {
  16. super();
  17. // TODO Auto-generated constructor stub
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. public int getAge() {
  26. return age;
  27. }
  28. public void setAge(int age) {
  29. this.age = age;
  30. }
  31. @Override
  32. public int hashCode() {
  33. final int prime = 31;
  34. int result = 1;
  35. result = prime * result + age;
  36. result = prime * result + ((name == null) ? 0 : name.hashCode());
  37. return result;
  38. }
  39. @Override
  40. public boolean equals(Object obj) {
  41. if (this == obj)
  42. return true;
  43. if (obj == null)
  44. return false;
  45. if (getClass() != obj.getClass())
  46. return false;
  47. StudentBean other = (StudentBean) obj;
  48. if (age != other.age)
  49. return false;
  50. if (name == null) {
  51. if (other.name != null)
  52. return false;
  53. } else if (!name.equals(other.name))
  54. return false;
  55. return true;
  56. }
  57. /**
  58. * 定义排序规则
  59. */
  60. @Override
  61. public int compareTo(StudentBean o) {
  62. // TODO Auto-generated method stub
  63. //自定义排序规则(0 ---我们地位是一样的 整数 ---你的地位比我大
  64. //负数 --- 你的地位比我小)
  65. return this.name.hashCode() - o.name.hashCode();
  66. }
  67. }
  1. private static void study03() {
  2. // TODO Auto-generated method stub
  3. TreeSet<StudentBean> data = new TreeSet<StudentBean>();
  4. StudentBean stu01 = new StudentBean("张三",18);
  5. StudentBean stu02 = new StudentBean("李四",15);
  6. StudentBean stu03 = new StudentBean("王五",23);
  7. data.add(stu01);
  8. data.add(stu02);
  9. data.add(stu03);
  10. System.out.println(data);
  11. }

自定义排序

自定义排序 和自然排序 都是用来集合完成排序的,区别在于:
自然排序,需要在元素身上实现Comparable
而自定义排序 ,需要程序员自己制定 排序比较器

  1. package com.woniuxy.java21.util;
  2. import java.util.Comparator;
  3. import com.woniuxy.java21.bean.StudentBean;
  4. /**
  5. * 自定义比较器,用来完成集合排序
  6. * @author Administrator
  7. *
  8. */
  9. public class InitStudentComparator implements Comparator<StudentBean>{
  10. /***
  11. * 0 我们地位相当
  12. * 正数 你的地位比我大 应该靠后
  13. * 负数 你的地位比我低 应该靠前
  14. */
  15. @Override
  16. public int compare(StudentBean o1, StudentBean o2) {
  17. // TODO Auto-generated method stub
  18. //升序规则
  19. return o1.getAge() - o2.getAge();
  20. }
  21. }
    package com.woniuxy.java21.study;
    import java.util.Iterator;
    import java.util.Set;
    import java.util.TreeSet;
    import com.woniuxy.java21.bean.StudentBean;
    import com.woniuxy.java21.util.InitStudentComparator;
    public class TreeSetStudy {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    //        study01();
    //        study02();
            study03();
        }
        private static void study03() {
            // TODO Auto-generated method stub
            TreeSet<StudentBean> data = new TreeSet<StudentBean>(new InitStudentComparator());
            StudentBean stu01 = new StudentBean("张三",18);
            StudentBean stu02 = new StudentBean("李四",15);
            StudentBean stu03 = new StudentBean("王五",23);
            data.add(stu01);
            data.add(stu02);
            data.add(stu03);
            System.out.println(data);
        }
        /**
         * TreeSet的排序规则
         */
        private static void study02() {
            // TODO Auto-generated method stub
            // 定义TreeSet的集合
            TreeSet<String> data = new TreeSet<String>();
            data.add("a");
            data.add("c");
            data.add("a");
            data.add("d");
            data.add("b");
            // 遍历(1)foreach
            for (String string : data) {
                System.out.println(string);
            }
        }
        private static void study01() {
            // TODO Auto-generated method stub
            // 定义TreeSet的集合
            TreeSet<String> data = new TreeSet<String>();
            data.add("a");
            data.add("c");
            data.add("a");
            data.add("d");
            data.add("b");
            // 得到集合长度
            System.out.println(data.size());
            // 判断集合中是否包含某一个元素
            System.out.println(data.contains("a"));
            // 判断集合是否为空
            System.out.println(data.isEmpty());
    //                data.remove("a");
            // 取得第1个元素
            System.out.println(data.first());
            // 取得最后1个元素
            System.out.println(data.last());
            // 严格返回比“b” 大的,该集合中的最小元素,如果没有此元素则返回 null (比我大的,但是又是最靠近我的)
            System.out.println(data.higher("b"));
            // 返回比我小的,也是最靠近我的
            System.out.println(data.lower("b"));
            // 取得集合中,比我小的所有元素
            System.out.println(data.headSet("c"));
            // 取得集合中,比我大的所有元素(但是包含自己)
            System.out.println(data.tailSet("b"));
            // 遍历(1)foreach
    //                for (String string : data) {
    //                    System.out.println(string);
    //                }
            // 遍历(2)迭代器
    //                Iterator<String> iterator = data.iterator();
    //                while(iterator.hasNext()) {
    //                    
    //                    String str = iterator.next();
    //                    
    //                    System.out.println(str);
    //                }
        }
    }

1.4 HashSet和TreeSet的区别

1、他们各自底层的实现原理不一样, HashSet的底层是HashMap,TreeSet的底层是TreeMap
2、各自数据结构也不一样,HashMap是数组 + 链表 + 红黑树,而TreeMap 直接就是红黑树
3、他们各自的去重原理也不一样,HashSet是采用Hash值结合equals()来完成去重,而TreeSet 他是通过比较器来去重
4、Hashset是无序的,而TreeSet有序的
5、Hashset可以存放null元素,而TreeSet是无法存放null元素

1.5 HashCode相关面试题

            TeacherBean teacherBean01 = new TeacherBean("马老师",25,30000);
            TeacherBean teacherBean02 = new TeacherBean("马老师",25,30000);
            //2个不同对象(地址不一样)
            System.out.println(teacherBean01 == teacherBean02);
            System.out.println(teacherBean01.equals(teacherBean02));
            System.out.println(teacherBean01.hashCode() == teacherBean01.hashCode());
            //不同的对象,可能拥有相同的Hash值,同一个对象,他们的Hash值一定一样

相同的Hashcode值,不一定就是同一个对象,但是同一个对象,它们的Hashcode值一定是相同
原因是:我们可能重写了Hashcode()算法

二、Map

2.1 Map简介

Map 和List Set一样都是JCF的一部分,List和Set是属于Collection体系的,而Map是个单独的体系(与Collection同级)

List,Set 中直接存储1组对象,但是Map中它是存储2组对象,分别是:key - value(k-v键值对)
无标题.png
其中key 和value 的关系是:1-1对应,1个key 对应 1个值
key 不允许重复,但是value 是可以重复,而且key 是允许放null的

2.2 Map公共的API

无标题.png

2.3 HashMap

HashMap 是Map接口中最为常用的实现类,它的结构是:数组 + 链表 + 红黑树(JDK1.8以后)(JDK1.8版本之前是数组 + 链表)

2.3.1 HashMap 的使用

    Map<String,String> datas = new HashMap<String,String>();

2.3.2 HashMap的底层结构细节

HashMap 定义了一个关于节点的数组,数组的初始容量是 16
当Hash数组中的元素的个数 >= 0.75 * 长度时,Hash数组就会自动扩容为2倍
单链变成红黑树的条件是:当数组的长度>= 64,并且单链的长度 >= 8个时,将转换为红黑树
无标题.png

2.3.3 HashMap常用API

    package com.woniuxy.java21.study;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    public class HashMapStudy {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Map<String,String> datas = new HashMap<String,String>();
            //向Map集合中添加元素
            datas.put("tea01", "陈老师");
            datas.put("tea02", "苍老师");
            //当相同的key,value的操作是覆盖
            datas.put("tea03", "张老师");
            datas.put("tea03", "王老师");
            //根据key 获得值
            System.out.println(datas.get("tea03"));
            //获得Map中元素的个数
            System.out.println(datas.size());
            //判断集合中是否有指定的key    或者value  
            System.out.println(datas.containsKey("tea01"));
            System.out.println(datas.containsValue("张老师"));
            //遍历Map(方式一)
    //        Set<Entry<String, String>> set = datas.entrySet();
    //        for (Entry<String, String> entry : set) {
    //            System.out.println("key=" + entry.getKey() + " value="+ entry.getValue());
    //        }
            //遍历Map(方式二)
    //        Set<String> keys = datas.keySet();
    //        for (String key : keys) {
    //            System.out.println(datas.get(key));
    //        }
            //根据key 删除 key - value的结构
            datas.remove("tea02");
            //返回集合中元素的个数
            System.out.println(datas.size());
        }
    }

注意

HashMap中作为key的对象,为了实现去重效果,一定要重写hashcode() 以及equals()方法

2.4 TreeMap

TreeMap 底层就不是:数组 + 链表 + 红黑树,而是它直接就是一个红黑树
它的API和HashMap 几乎一致,它的区别是:它可以自然排序或自定义排序而已

    package com.woniuxy.java21.study;
    import java.util.Map;
    import java.util.Set;
    import java.util.TreeMap;
    import com.woniuxy.java21.bean.CarBean;
    public class TreeMapStudy {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            CarBean car01 = new CarBean("奥迪", "Audi", "小轿车");
            CarBean car02 = new CarBean("奥拓", "Auto", "小轿车");
            CarBean car03 = new CarBean("阿斯顿.马丁", "Aston martin", "小轿车");
            CarBean car04 = new CarBean("宝马", "Bmw", "小轿车");
            CarBean car05 = new CarBean("奔驰", "Benz", "小轿车");
            CarBean car06 = new CarBean("比亚迪", "Byd", "小轿车");
            CarBean car07 = new CarBean("哈弗", "Haver", "小轿车");
            CarBean car08 = new CarBean("悍马", "Hummer", "小轿车");
            CarBean car09 = new CarBean("红旗", "Hongqi", "小轿车");
            Map<CarBean,String> datas = new TreeMap<CarBean,String>();
            datas.put(car01, "小苍");
            datas.put(car02, "小王");
            datas.put(car03, "翠花");
            datas.put(car04, "小白");
            datas.put(car05, "小苍");
            datas.put(car08, "小黑");
            datas.put(car06, "小苍");
            datas.put(car07, "小黄");
            datas.put(car09, "小红");
            //遍历
            Set<CarBean> keys = datas.keySet();
            for (CarBean carBean : keys) {
                System.out.println(carBean);
            }
        }
    }

2.5 HashTable

HashTable 也是Map接口的实现类之一,它的用法和HashMap是一样的,区别在于:它定义的方法使用了synchronized关键字,表示:它线程安全,但是效率低下

2.6 HashMap、TreeMap 、HashTable 区别

首先,他们3个都是Map接口的实现类,只是各自的底层上有些区别:
1、从底层结构来讲:
HashMap底层是数组 + 单链表 + 红黑二叉树来实现的
TreeMap底层是红黑二叉树
HashTable 底层是:数组 + 单链表
2、HashMap 无法针对数据进行自动排序,而TreeMap是可以根据元素提供的比较器,完成自然排序或自定义排序
3、HashMap 没有提供synchronized关键字,而HashTable提供该关键字,所以
HashTable是线程安全的,但是效率不高。HashMap的效率相对较高
4、HashTable、TreeMap不允许放置null值和null 键,HashMap 允许放置null值 和null键

2.7 Properties (属性)

它也是一种key-value结构的集合,它是HashTable的子类,它同HashTable在某些规则上是一样,也是添加了synchronized关键字的。例外,同样,不允许放置null 值 和null键
它的主要使用场景:从配置文件中 加载内容到程序来中
mysql.properties:

    jdbc.url=1231wrwer
    jdbc.userName=userpu
    jdbc.password=123456
    jdbc.driverClassName=234
    package com.woniuxy.java21.study;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.Properties;
    import com.woniuxy.java21.bean.CarBean;
    import com.woniuxy.java21.bean.StudentBean;
    public class PropertiesStudy {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    //        study01();
            study02();
        }
        private static void study02() {
            // TODO Auto-generated method stub
            Properties props = new Properties();
            FileInputStream fis = null;
            try {
    //            File.separatorChar 代表 \\ 在windows系统中
                String path = System.getProperty("user.dir") + File.separatorChar + "src" + File.separatorChar +"mysql.properties" ;
    //            System.out.println(path);
                File file = new File(path);
                fis = new FileInputStream(file);
                props.load(fis);
                System.out.println(props.get("jdbc.url"));
                System.out.println(props.get("jdbc.userName"));
                System.out.println(props.get("jdbc.password"));
                System.out.println(props.get("jdbc.driverClassName"));
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }finally {
                try {
                    fis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        private static void study01() {
            // TODO Auto-generated method stub
    //        Properties props = new Properties();
    //        //同样可以放置null值和null键
    //        props.put(null, null);
    //        //也可以放置其他东西
    //        props.put(new CarBean(), new StudentBean());
    //        props.put("userName", "小张");
    //        System.out.println(props.get("userName"));
        }
    }