百木园-与人分享,
就是让自己快乐。

集合总结

2.Collection集合

2.1数组和集合的区别(理解)

  • 相同点

    都是容器,可以存储多个数据

  • 不同点

    • 数组的长度是不可变的,集合的长度是可变的

    • 数组可以存基本数据类型和引用数据类型

      集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类

2.2集合类体系结构(理解)

2.3Collection 集合概述和使用(应用)

  • Collection集合概述

    • 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素

    • JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现

  • 创建Collection集合的对象

    • 多态的方式

    • 具体的实现类ArrayList

  • Collection集合常用方法

    方法名 说明
    boolean add(E e) 添加元素
    boolean remove(Object o) 从集合中移除指定的元素
    boolean removeIf(Object o) 根据条件进行移除
    void clear() 清空集合中的元素
    boolean contains(Object o) 判断集合中是否存在指定的元素
    boolean isEmpty() 判断集合是否为空
    int size() 集合的长度,也就是集合中元素的个数

2.4迭代器(应用)

  • 迭代器介绍

    • 迭代器,集合的专用遍历方式

    • Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到,迭代器对象一旦被创建,默认指向集合的0索引位置.

  • Iterator中的常用方法

    ​ boolean hasNext(): 判断当前位置是否有元素可以被取出​ E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置

  • 示例代码

    public class MyCollectionDemo3 {
       public static void main(String[] args) {
           Collection<String> list = new ArrayList<>();
           list.add(\"a\");
           list.add(\"b\");
           list.add(\"c\");
           list.add(\"d\");
           list.add(\"e\");

           //1,获得迭代器的对象
           //迭代器对象一旦被创建,默认指向集合的0索引位置
           Iterator<String> it = list.iterator();

           //2.利用迭代器里面的方法进行遍历
           /*
               boolean hasNext()   判断当前是否还有元素
               E next()           取出当前元素,并指向下一个元素
            */
           while(it.hasNext()){
               System.out.println(it.next());
          }

      }
    }
  • 迭代器原理

  • 迭代器中删除的方法

    ​ void remove(): 删除迭代器对象当前指向的元素


    public class IteratorDemo2 {
       public static void main(String[] args) {
           ArrayList<String> list = new ArrayList<>();
           list.add(\"a\");
           list.add(\"b\");
           list.add(\"b\");
           list.add(\"c\");
           list.add(\"d\");

           Iterator<String> it = list.iterator();
           while(it.hasNext()){
               String s = it.next();
               if(\"b\".equals(s)){
                   //指向谁,那么此时就删除谁.
                   it.remove();
              }
          }
           System.out.println(list);
      }
    }

2.5增强for循环(应用)

  • 介绍

    • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

    • 实现Iterable接口的类才可以使用迭代器和增强for

    • 简化数组和Collection集合的遍历

  • 格式

    ​ for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {

    ​ // 已经将当前遍历到的元素封装到变量中了,直接使用变量即可

    ​ }

  • 代码


    public class MyCollectonDemo1 {
       public static void main(String[] args) {
           ArrayList<String> list =  new ArrayList<>();
           list.add(\"a\");
           list.add(\"b\");
           list.add(\"c\");
           list.add(\"d\");
           list.add(\"e\");
           list.add(\"f\");

           //1,数据类型一定是集合或者数组中元素的类型
           //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
           //3,list就是要遍历的集合或者数组
           for(String str : list){
               System.out.println(str);
          }
      }
    }
  • 注意事项


    public class MyCollectionDemo7 {
       public static void main(String[] args) {

           ArrayList<String> list =  new ArrayList<>();
           list.add(\"a\");
           list.add(\"b\");
           list.add(\"c\");
           list.add(\"d\");

           //str是第三方变量,对第三方变量的修改 不会影响集合原有值
           for(String str : list){
               str = \"q\";
               System.out.println(str);
          }

           //集合或数组名.for   敲回车,快速生成增强for格式
           for (String s : list) {
               System.out.println(s);
          }

           //System.out.println(list);
      }
    }
  • 三种遍历集合方式总结

    • 如果需要操作索引,使用普通for循环

    • 如果在遍历的过程中需要删除元素,请使用迭代器

    • 如果仅仅只是遍历,则使用增强for

2.6Collection练习(应用)


public class MyCollectionDemo8 {
   public static void main(String[] args) {
       ArrayList<Student> list = new ArrayList<>();

       list.add(new Student(\"小皮同学\",23));
       list.add(new Student(\"小路同学\",31));
       list.add(new Student(\"小贾同学\",33));

       //迭代器的方式进行遍历
       Iterator<Student> it = list.iterator();
       while(it.hasNext()){
           Student s = it.next();
           System.out.println(s);
      }

       System.out.println(\"-------------------------\");

       //增强for
       for (Student student : list) {
           System.out.println(student);
      }

       System.out.println(\"--------------------------\");

       //普通for循环
       for (int i = 0; i < list.size(); i++) {
           System.out.println(list.get(i));
      }
  }
}

 

3.List集合

3.1List集合的概述和特点(记忆)

  • List集合的概述

    • 有序集合,这里的有序指的是存取顺序

    • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素

    • 与Set集合不同,列表通常允许重复的元素

  • List集合的特点

    • 存取有序

    • 可以重复

    • 有索引

  • 示例代码


    public class MyListDemo1 {
       public static void main(String[] args) {
           List<String> list = new ArrayList<>();
           list.add(\"aaa\");
           list.add(\"bbb\");
           list.add(\"ccc\");

           Iterator<String> it = list.iterator();
           while(it.hasNext()){
               String s = it.next();
               System.out.println(s);
          }

           System.out.println(\"---------------------\");

           for (String s : list) {
               System.out.println(s);
          }
      }
    }

3.2List集合的特有方法(应用)

  • 方法介绍

    方法名 描述
    void add(int index,E element) 在此集合中的指定位置插入指定的元素
    E remove(int index) 删除指定索引处的元素,返回被删除的元素
    E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
    E get(int index) 返回指定索引处的元素
  • 示例代码


    public class MyListDemo2 {
       public static void main(String[] args) {
           List<String> list = new ArrayList<>();
           list.add(\"aaa\");
           list.add(\"bbb\");
           list.add(\"ccc\");
           method1(list);
           method2(list);
           method3(list);
           method4(list);
      }

       private static void method4(List<String> list) {
           //E get(int index) 返回指定索引处的元素
           String s = list.get(0);
           System.out.println(s);
      }

       private static void method3(List<String> list) {
           //E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
           //被替换的那个元素,在集合中就不存在了.
           String result = list.set(0, \"qqq\");
           System.out.println(result);
           System.out.println(list);
      }

       private static void method2(List<String> list) {
           //E remove(int index) 删除指定索引处的元素,返回被删除的元素
           //在List集合中有两个删除的方法
           //第一个 删除指定的元素,返回值表示当前元素是否删除成功
           //第二个 删除指定索引的元素,返回值表示实际删除的元素
           String s = list.remove(0);
           System.out.println(s);
           System.out.println(list);
      }

       private static void method1(List<String> list) {
           //void add(int index,E element) 在此集合中的指定位置插入指定的元素
           //原来位置上的元素往后挪一个索引.
           list.add(0,\"qqq\");
           System.out.println(list);
      }
    }

4.数据结构

4.1数据结构之栈和队列(记忆)

  • 栈结构

    ​ 先进后出

  • 队列结构

    ​ 先进先出

4.2数据结构之数组和链表(记忆)

  • 数组结构

    ​ 查询快、增删慢 arraylist

  • 链表结构

    ​ 查询慢、增删快

    添加元素

    查询元素

5.List集合的实现类

5.1List集合子类的特点(记忆)

  • ArrayList集合

    ​ 底层是数组结构实现,查询快、增删慢

  • ArrayList源码分析

    ArrayList使用无参构造创建时,数组的长度为零。当ArrayList第一次添加元素时,创建一个新的长度为10的数组,后续每次数组要进行扩容时,每次扩大为原来的1.5倍。

  • LinkedList集合

    ​ 底层是链表结构实现,查询慢、增删快

  • LinkedList示例代码


    public class MyLinkedListDemo3 {
       public static void main(String[] args) {
           LinkedList<String> list = new LinkedList<>();
           list.add(\"aaa\");
           list.add(\"bbb\");
           list.add(\"ccc\");

           for (int i = 0; i < list.size(); i++) {
               System.out.println(list.get(i));
          }
           System.out.println(\"-------------------------\");
           Iterator<String> it = list.iterator();
           while (it.hasNext()) {
               String s = it.next();
               System.out.println(s);
          }
           System.out.println(\"--------------------------\");
           for (String s : list) {
               System.out.println(s);
          }
      }
    }

5.2LinkedList集合的特有功能(应用)

  • 特有方法

    方法名 说明
    public void addFirst(E e) 在该列表开头插入指定的元素
    public void addLast(E e) 将指定的元素追加到此列表的末尾
    public E getFirst() 返回此列表中的第一个元素
    public E getLast() 返回此列表中的最后一个元素
    public E removeFirst() 从此列表中删除并返回第一个元素
    public E removeLast() 从此列表中删除并返回最后一个元素
  • 示例代码


    public class MyLinkedListDemo4 {
       public static void main(String[] args) {
           LinkedList<String> list = new LinkedList<>();
           list.add(\"aaa\");
           list.add(\"bbb\");
           list.add(\"ccc\");
    //       public void addFirst(E e) 在该列表开头插入指定的元素
           //method1(list);

    //       public void addLast(E e) 将指定的元素追加到此列表的末尾
           //method2(list);

    //       public E getFirst() 返回此列表中的第一个元素
    //       public E getLast() 返回此列表中的最后一个元素
           //method3(list);

    //       public E removeFirst() 从此列表中删除并返回第一个元素
    //       public E removeLast() 从此列表中删除并返回最后一个元素
           //method4(list);
         
      }

       private static void method4(LinkedList<String> list) {
           String first = list.removeFirst();
           System.out.println(first);

           String last = list.removeLast();
           System.out.println(last);

           System.out.println(list);
      }

       private static void method3(LinkedList<String> list) {
           String first = list.getFirst();
           String last = list.getLast();
           System.out.println(first);
           System.out.println(last);
      }

       private static void method2(LinkedList<String> list) {
           list.addLast(\"www\");
           System.out.println(list);
      }

       private static void method1(LinkedList<String> list) {
           list.addFirst(\"qqq\");
           System.out.println(list);
      }
    }

6.泛型

1.1泛型概述

  • 泛型的介绍

    泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制

  • 泛型的好处

    1. 把运行时期的问题提前到了编译期间

    2. 避免了强制类型转换

  • 示例代码


    /**
    * 不写泛型的弊端
    */
    public class GenericitySummarize {
       public static void main(String[] args) {
           ArrayList list = new ArrayList();
           list.add(\"aaa\");
           list.add(\"bbb\");
           list.add(\"ccc\");
           list.add(123);

           Iterator it = list.iterator();
           while(it.hasNext()){
               String next = (String) it.next();
               int len = next.length();
               System.out.println(len);
          }
      }
    }

7.Set集合

2.1Set集合概述和特点【应用】

  • 不可以存储重复元素

  • 存取顺序不一致

  • 没有索引,不能使用普通for循环遍历,跟索引相关的方法也没有。

2.2Set集合的使用【应用】

存储字符串并遍历


public class MySet1 {
   public static void main(String[] args) {
    //创建集合对象
       Set<String> set = new TreeSet<>();
    //添加元素
       set.add(\"ccc\");
       set.add(\"aaa\");
       set.add(\"aaa\");
       set.add(\"bbb\");

//       for (int i = 0; i < set.size(); i++) {
//           //Set集合是没有索引的,所以不能使用通过索引获取元素的方法
//       }
     
    //遍历集合
       Iterator<String> it = set.iterator();
       while (it.hasNext()){
           String s = it.next();
           System.out.println(s);
      }
       System.out.println(\"-----------------------------------\");
       for (String s : set) {
           System.out.println(s);
      }
  }
}

8.TreeSet集合

3.1TreeSet集合概述和特点【应用】

  • 不可以存储重复元素

  • 没有索引

  • 不可以重复

  • 可以将元素按照规则进行排序

    • TreeSet():根据其元素的自然排序进行排序

    • TreeSet(Comparator comparator) :根据指定的比较器进行排序

3.2TreeSet集合基本使用【应用】

存储Integer类型的整数并遍历


public class MyTreeSet1 {
   public static void main(String[] args) {
       TreeSet<Integer> ts = new TreeSet<>();
       ts.add(5);
       ts.add(3);
       ts.add(4);
       ts.add(1);
       ts.add(2);
       System.out.println(ts);
  }
}

3.3自然排序Comparable的使用【应用】

  • 案例需求

    • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法

    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 实现步骤

    1. 使用空参构造创建TreeSet集合

      • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的

    2. 自定义的Student类实现Comparable接口

      • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法

    3. 重写接口中的compareTo方法

      • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

  • 代码实现

    学生类


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

       public Student() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public String toString() {
           return \"Student{\" +
                   \"name=\'\" + name + \'\\\'\' +
                   \", age=\" + age +
                   \'}\';
      }

       @Override
       public int compareTo(Student o) {
           //按照对象的年龄进行排序
           //主要判断条件: 按照年龄从小到大排序
           int result = this.age - o.age;
           //次要判断条件: 年龄相同时,按照姓名的字母顺序排序
           result = result == 0 ? this.name.compareTo(o.getName()) : result;
           return result;
      }
    }

    测试类


    public class MyTreeSet2 {
       public static void main(String[] args) {
           //创建集合对象
           TreeSet<Student> ts = new TreeSet<>();
       //创建学生对象
           Student s1 = new Student(\"zhangsan\",28);
           Student s2 = new Student(\"lisi\",27);
           Student s3 = new Student(\"wangwu\",29);
           Student s4 = new Student(\"zhaoliu\",28);
           Student s5 = new Student(\"qianqi\",30);
    //把学生添加到集合
           ts.add(s1);
           ts.add(s2);
           ts.add(s3);
           ts.add(s4);
           ts.add(s5);
    //遍历集合
           for (Student student : ts) {
               System.out.println(student);
          }
      }
    }
  • 自然排序原理

3.4比较器排序Comparator的使用【应用】

  • 案例需求

    • 存储老师对象并遍历,创建TreeSet集合使用带参构造方法

    • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 实现步骤

    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的

    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法

    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

  • 代码实现

    老师类


    public class Teacher {
       private String name;
       private int age;

       public Teacher() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public String toString() {
           return \"Teacher{\" +
                   \"name=\'\" + name + \'\\\'\' +
                   \", age=\" + age +
                   \'}\';
      }
    }

    测试类


    public class MyTreeSet4 {
       public static void main(String[] args) {
        //创建集合对象
           TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
               @Override
               public int compare(Teacher o1, Teacher o2) {
                   //o1表示现在要存入的那个元素
                   //o2表示已经存入到集合中的元素
                 
                   //主要条件
                   int result = o1.getAge() - o2.getAge();
                   //次要条件
                   result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                   return result;
              }
          });
    //创建老师对象
           Teacher t1 = new Teacher(\"zhangsan\",23);
           Teacher t2 = new Teacher(\"lisi\",22);
           Teacher t3 = new Teacher(\"wangwu\",24);
           Teacher t4 = new Teacher(\"zhaoliu\",24);
    //把老师添加到集合
           ts.add(t1);
           ts.add(t2);
           ts.add(t3);
           ts.add(t4);
    //遍历集合
           for (Teacher teacher : ts) {
               System.out.println(teacher);
          }
      }
    }

3.5两种比较方式总结【理解】

  • 两种比较方式小结

    • 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序

    • 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序

    • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,使用比较器排序

  • 两种方式中关于返回值的规则

    • 如果返回值为负数,表示当前存入的元素是较小值,存左边

    • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存

    • 如果返回值为正数,表示当前存入的元素是较大值,存右边

  • 二种方式如何确定是升序还是降序

    • 自然排序


      public int compareTo(Student o) {
         //this在前,参数在后,表示升序
         //this在后,参数在前,表示降序
         //根据age年龄升序,当年龄一样的时候,根据name姓名进行升序
         int result = this.age - o.age;
         result = result == 0 ? this.name.compareTo(o.name) : result;
         return result;
      }

    • 比较器排序


      public int compare(String o1, String o2) {
          // o1在前表示升序, o1在后表示降序。
          int result = o1.length() - o2.length();
          result = result == 0 ? o1.compareTo(o2) : result;
          return result;
      }
  • 示例代码

    存入四个字符串,\"c\" \"ab\" \"df\" \"qwer\"按照长度排序,如果长度一样则按照首字母排序


    public class MyTreeSet5 {
       public static void main(String[] args) {
           /*TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
               @Override
               public int compare(String o1, String o2) {
                   int result = o1.length() - o2.length();
                   result = result == 0 ? o1.compareTo(o2) : result;
                   return result;
               }
           });*/
           //TreeSet带参构造 传递一个比较器对象 使用lambad表达式方式
           TreeSet<String> ts = new TreeSet<>(
                  (String o1, String o2) -> {
                       int result = o1.length() - o2.length();
                       result = result == 0 ? o1.compareTo(o2) : result;
                       return result;
                  }
          );

           ts.add(\"c\");
           ts.add(\"ab\");
           ts.add(\"df\");
           ts.add(\"qwer\");

           System.out.println(ts);
      }
    }

9.数据结构

4.1二叉树【理解】

  • 关于树的一些专业名称

    • 节点: 在树结构中,每一个元素称之为节点

    • 根节点:最顶层的节点,我们叫做根节点

    • 度: 每一个节点的子节点数量称之为度

    • 树高:一个树的层数,我们叫做树高

  • 二叉树的特点

    任意一个节点的度要小于等于2,即任意一个节点最多只能有二个子节点。

  • 二叉树结构图

4.2二叉查找树【理解】

  • 二叉查找树的特点

    • 每一个节点上最多有两个子节点

    • 左子树上所有节点的值都小于根节点的值

    • 右子树上所有节点的值都大于根节点的值

  • 二叉查找树结构图

  • 二叉查找树和二叉树对比结构图

  • 二叉查找树添加节点规则

    • 小的存左边

    • 大的存右边

    • 一样的不存

4.3平衡二叉树【理解】

  • 平衡二叉树的特点

    • 是一个二叉查找树

    • 任意节点的左右两个子树的高度差不超过1

  • 平衡二叉树旋转

    • 旋转触发时机

      • 当添加一个节点之后,该树不再是一颗平衡二叉树

    • 左旋

      • 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

    • 右旋

      • 就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点

  • 平衡二叉树和二叉查找树对比结构图

  • 平衡二叉树旋转的四种情况

    • 左左

      • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行右旋即可

    • 左右

      • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋

    • 右右

      • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

      • 如何旋转: 直接对整体进行左旋即可

    • 右左

      • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

      • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

4.3红黑树【理解】

  • 红黑树的特点

    • 是一个二叉查找树

    • 每一个节点可以是红或者黑

    • 红黑树不是高度平衡的,它的平衡是通过\"自己的红黑规则\"进行实现的

  • 红黑树的红黑规则有哪些

    1. 每一个节点或是红色的,或者是黑色的

    2. 根节点必须是黑色

    3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的

    4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)

    5. 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

  • 红黑树添加节点的默认颜色

    • 添加节点时,默认为红色,效率高

  • 红黑树添加节点后如何保持红黑规则

    • 根节点位置

      • 直接变为黑色

    • 非根节点位置

      • 父节点为黑色

        • 不需要任何操作,默认红色即可

      • 父节点为红色

        • 叔叔节点为红色

          1. 将\"父节点\"设为黑色,将\"叔叔节点\"设为黑色

          2. 将\"祖父节点\"设为红色

          3. 如果\"祖父节点\"为根节点,则将根节点再次变成黑色

        • 叔叔节点为黑色

          1. 将\"父节点\"设为黑色

          2. 将\"祖父节点\"设为红色

          3. 以\"祖父节点\"为支点进行旋转

10.HashSet集合

1.1HashSet集合概述和特点(应用)

  • 底层数据结构是哈希表

  • 存取无序

  • 不可以存储重复元素

  • 没有索引,不能使用普通for循环遍历

1.2HashSet集合的基本应用(应用)


public class HashSetDemo {
   public static void main(String[] args) {
       //创建集合对象
       HashSet<String> set = new HashSet<String>();

       //添加元素
       set.add(\"hello\");
       set.add(\"world\");
       set.add(\"java\");
       set.add(\"java\");
       set.add(\"java\");
       set.add(\"java\");

       //迭代器遍历
       Iterator<String> it = set.iterator();
       while (it.hasNext()) {
           String next = it.next();
           System.out.println(next);
      }

       System.out.println(\"=================\");
       
       //增强for遍历
       for (String s : set) {
           System.out.println(s);
      }
  }
}

1.3哈希值(理解)

  • 哈希值简介

    ​ 根据对象的地址值或者属性值计算出来的一个int类型的整数

  • 如何获取哈希值

    ​ Object类中的public int hashCode():返回对象的哈希码值

  • 哈希值的特点

    • 如果没有重写hashcode方法,那么就根据对象的地址值进行计算哈希值

      针对同一个对象,返回的哈希值相同,针对不同的对象,返回的哈希值不同

    • 如果重写了hashcode方法,一般都是根据对象的属性值来进行重写。

      如果不同对象的属性值相同,那么它们的哈希值也是一样的。

  • 示例代码


    public class HashSetDemo2 {
       public static void main(String[] args) {
           Student s1 = new Student(\"张三\",23);
           Student s2 = new Student(\"张三\",23);
           Student s3 = new Student(\"李四\",24);

           //如果Student类没有重写hashcode方法,则根据地址值计算哈希值
           //如果重写了则一般根据属性值进行计算哈希值
           System.out.println(s1.hashCode());
           System.out.println(s2.hashCode());
           System.out.println(s3.hashCode());
      }
    }

    public class Student {
       private String name;
       private int age;

       public Student() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public boolean equals(Object o) {
           if (this == o) return true;
           if (o == null || getClass() != o.getClass()) return false;

           Student student = (Student) o;

           if (age != student.age) return false;
           return name != null ? name.equals(student.name) : student.name == null;
      }

       // 可以对Object类的hashCode()方法进行重写
       // 根据对象的属性值计算哈希值
       @Override
       public int hashCode() {
           int result = name != null ? name.hashCode() : 0;
           result = 31 * result + age;
           return result;
      }

       @Override
       public String toString() {
           return \"Student{\" +
                   \"name=\'\" + name + \'\\\'\' +
                   \", age=\" + age +
                   \'}\';
      }
    }

1.4哈希表结构(理解)

  • JDK1.8以前

    ​ 数组 + 链表

    ​ 默认长度16,加载因子0.75 ,16*0.75=12 每次扩容2倍 头插法

     

  • JDK1.8以后

    ​ 尾插法(七上八下)

    • 节点个数小于等于8个

      ​ 数组 + 链表

    • 节点个数大于8个

      ​ 数组 + 红黑树

     

1.5HashSet集合存储学生对象并遍历(应用)

  • 案例需求

    • 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

    • 要求:学生对象的成员变量值相同,我们就认为是同一个对象

  • 代码实现

    学生类


    public class Student {
       private String name;
       private int age;

       public Student() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public boolean equals(Object o) {
           if (this == o) return true;
           if (o == null || getClass() != o.getClass()) return false;

           Student student = (Student) o;

           if (age != student.age) return false;
           return name != null ? name.equals(student.name) : student.name == null;
      }

       @Override
       public int hashCode() {
           int result = name != null ? name.hashCode() : 0;
           result = 31 * result + age;
           return result;
      }
    }

    测试类


    /*
       创建一个存储学生对象的集合,存储多个学生对象,使用程序实现控制台遍历集合
       要求:学生对象的成员变量值相同,我们就认为是同一个对象。

       结论:HashSet集合存储自定义类型对象,那么必须重新hashcode和equals方法。
    */
    public class HashSetTest1 {
       public static void main(String[] args) {
           HashSet<Student> hs = new HashSet<>();
           hs.add(new Student(\"xiaohei\", 23));
           hs.add(new Student(\"xiaohei\", 23));
           hs.add(new Student(\"xiaomei\", 23));
           for (Student s : hs) {
               System.out.println(s);
          }
      }
    }
  • 总结

    ​ HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

1.6 Set集合小结

 

11.Map集合

2.1Map集合概述和特点(理解)

  • interface Map<K,V> K:键的类型;V:值的类型

  • 键不可以重复,值可以重复

  • 键和值一一对应,通过一个键能找到对应的值

  • 键和值这个整体,我们称之为键值对,或者又叫做Entry对象

  • 示例代码


    public class MyMap1 {
       public static void main(String[] args) {
           Map<String,String> map = new HashMap<>();

           map.put(\"itheima001\",\"小智\");
           map.put(\"itheima002\",\"小美\");
           map.put(\"itheima003\",\"大胖\");

           System.out.println(map);
      }
    }

2.2Map集合的常用方法(应用)

  • 方法介绍

    方法名 说明
    V put(K key,V value) 添加元素,当key存在时进行替换
    V remove(Object key) 根据键删除键值对元素
    void clear() 移除所有的键值对元素
    boolean containsKey(Object key) 判断集合是否包含指定的键
    boolean containsValue(Object value) 判断集合是否包含指定的值
    boolean isEmpty() 判断集合是否为空
    int size() 集合的长度,也就是集合中键值对的个数
  • 示例代码


    public class MyMap2 {
       public static void main(String[] args) {
           Map<String,String> map = new HashMap<>();
           map.put(\"itheima001\",\"小智\");
           map.put(\"itheima002\",\"小美\");
           map.put(\"itheima003\",\"大胖\");
           map.put(\"itheima004\",\"小黑\");
           map.put(\"itheima005\",\"大师\");

           //V put(K key,V value)   添加元素
           method1(map);
           //V remove(Object key)   根据键删除键值对元素
           method2(map);
           //void clear()           移除所有的键值对元素
           method3(map);
           //boolean containsKey(Object key) 判断集合是否包含指定的键
           method4(map);
           //boolean containsValue(Object value) 判断集合是否包含指定的值
           method5(map);
           //boolean isEmpty()       判断集合是否为空
           method6(map);
           //int size()             集合的长度,也就是集合中键值对的个数
           method7(map);
      }

       private static void method7(Map<String, String> map) {
           //int size()             集合的长度,也就是集合中键值对的个数
           int size = map.size();
           System.out.println(size);
      }

       private static void method6(Map<String, String> map) {
           //boolean isEmpty()       判断集合是否为空
           boolean empty1 = map.isEmpty();
           System.out.println(empty1);//false

           map.clear();
           boolean empty2 = map.isEmpty();
           System.out.println(empty2);//true
      }

       private static void method5(Map<String, String> map) {
           //boolean containsValue(Object value) 判断集合是否包含指定的值
           boolean result1 = map.containsValue(\"aaa\");
           boolean result2 = map.containsValue(\"小智\");
           System.out.println(result1);
           System.out.println(result2);
      }

       private static void method4(Map<String, String> map) {
           //boolean containsKey(Object key) 判断集合是否包含指定的键
           boolean result1 = map.containsKey(\"itheima001\");
           boolean result2 = map.containsKey(\"itheima006\");
           System.out.println(result1);
           System.out.println(result2);
      }

       private static void method3(Map<String, String> map) {
           //void clear()           移除所有的键值对元素
           map.clear();
           System.out.println(map);
      }

       private static void method2(Map<String, String> map) {
           //V remove(Object key)   根据键删除键值对元素
           String s = map.remove(\"itheima001\");
           System.out.println(s);
           System.out.println(map);
      }

       private static void method1(Map<String, String> map) {
           //V put(K key,V value)   添加元素
           //如果要添加的键不存在,那么会把键值对都添加到集合中
           //如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
           String s = map.put(\"itheima001\", \"aaa\");
           System.out.println(s);
           System.out.println(map);
      }
    }

2.3Map集合的遍历方法(应用)

  • 方法介绍

    方法名 说明
    V get(Object key) 根据键获取值
    Set<K> keySet() 获取所有键的集合
    Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
    K getKey() 通过entry对象获取键
    V getValue() 通过entry对象获取值

2.4Map集合的遍历(方式1)(应用)

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合

      • 把所有的丈夫给集中起来

      • 遍历丈夫的集合,获取到每一个丈夫

      • 根据丈夫去找对应的妻子

  • 步骤分析

    • 获取所有键的集合。用keySet()方法实现

    • 遍历键的集合,获取到每一个键。用增强for实现

    • 根据键去找值。用get(Object key)方法实现

  • 代码实现


    public class MyMap3 {
       public static void main(String[] args) {
           //创建集合并添加元素
           Map<String,String> map = new HashMap<>();
         map.put(\"1号丈夫\",\"1号妻子\");
           map.put(\"2号丈夫\",\"2号妻子\");
           map.put(\"3号丈夫\",\"3号妻子\");
           map.put(\"4号丈夫\",\"4号妻子\");
           map.put(\"5号丈夫\",\"5号妻子\");

           //获取到所有的键
           Set<String> keys = map.keySet();
           //遍历Set集合得到每一个键
           for (String key : keys) {
               //通过每一个键key,来获取到对应的值
               String value = map.get(key);
               System.out.println(key + \"---\" + value);
          }
      }
    }

2.5Map集合的遍历(方式2)(应用)

  • 遍历思路

    • 我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合

      • 获取所有结婚证的集合

      • 遍历结婚证的集合,得到每一个结婚证

      • 根据结婚证获取丈夫和妻子

  • 步骤分析

    • 获取所有键值对对象的集合

      • Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合

    • 遍历键值对对象的集合,得到每一个键值对对象

      • 用增强for实现,得到每一个Map.Entry

    • 根据键值对对象获取键和值

      • 用getKey()得到键

      • 用getValue()得到值

  • 代码实现


    public class MyMap4 {
       public static void main(String[] args) {
           //创建集合并添加元素
           Map<String, String> map = new HashMap<>();
           map.put(\"1号丈夫\", \"1号妻子\");
           map.put(\"2号丈夫\", \"2号妻子\");
           map.put(\"3号丈夫\", \"3号妻子\");
           map.put(\"4号丈夫\", \"4号妻子\");
           map.put(\"5号丈夫\", \"5号妻子\");

           //首先要获取到所有的键值对对象。
           //Set集合中装的是键值对对象(Entry对象)
           //而Entry里面装的是键和值
           Set<Map.Entry<String, String>> entries = map.entrySet();

           //遍历Set集合,得到每一个键值对对象
           for (Map.Entry<String, String> entry : entries) {
               //通过entry对象的getKey获取键,getValue()获取值
               String key = entry.getKey();
               String value = entry.getValue();
               System.out.println(key + \"---\" + value);
          }
      }
    }

12.HashMap集合

3.1HashMap集合概述和特点(理解)

  • HashMap底层是哈希表结构的

  • 依赖hashCode方法和equals方法保证键的唯一

  • 如果键要存储的是自定义对象,需要重写hashCode和equals方法

  • 底层结构与HashSet一样

3.2HashMap集合应用案例(应用)

  • 案例需求

    • 创建一个HashMap集合,键是学生对象(Student),值是居住地 (String)。存储多个元素,并遍历。

    • 要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象

  • 代码实现

    学生类


    public class Student {
       private String name;
       private int age;

       public Student() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public boolean equals(Object o) {
           if (this == o) return true;
           if (o == null || getClass() != o.getClass()) return false;

           Student student = (Student) o;

           if (age != student.age) return false;
           return name != null ? name.equals(student.name) : student.name == null;
      }

       @Override
       public int hashCode() {
           int result = name != null ? name.hashCode() : 0;
           result = 31 * result + age;
           return result;
      }
    }

    测试类


    public class MyMap5 {
       public static void main(String[] args) {
           HashMap<Student,String> hm = new HashMap<>();

           Student s1 = new Student(\"xiaohei\",23);
           Student s2 = new Student(\"dapang\",24);
           Student s3 = new Student(\"xiaomei\",22);

           hm.put(s1,\"江苏\");
           hm.put(s2,\"北京\");
           hm.put(s3,\"天津\");

           //第一种:先获取到所有的键,再通过每一个键来找对应的值
           Set<Student> keys = hm.keySet();
           for (Student key : keys) {
               String value = hm.get(key);
               System.out.println(key + \"----\" + value);
          }

           System.out.println(\"---------------------------------\");

           //第二种:先获取到所有的键值对对象。再获取到里面的每一个键和每一个值
           Set<Map.Entry<Student, String>> entries = hm.entrySet();
           for (Map.Entry<Student, String> entry : entries) {
               Student key = entry.getKey();
               String value = entry.getValue();
               System.out.println(key + \"----\" + value);
          }

           System.out.println(\"---------------------------------\");

           //第三种:
           hm.forEach(
                  (Student student, String s) -> {
                       System.out.println(student + \"---\" + s);
                  }
          );

      }
    }

 

13.TreeMap集合

4.1TreeMap集合概述和特点(理解)

  • TreeMap底层是红黑树结构

  • 依赖自然排序或者比较器排序,对键进行排序

  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

4.2TreeMap集合应用案例(应用)

  • 案例需求

    • 创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历

    • 要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序

  • 代码实现

    学生类


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

       public Student() {
      }

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

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public int getAge() {
           return age;
      }

       public void setAge(int age) {
           this.age = age;
      }

       @Override
       public String toString() {
           return \"Student{\" +
                   \"name=\'\" + name + \'\\\'\' +
                   \", age=\" + age +
                   \'}\';
      }

       @Override
       public int compareTo(Student o) {
           //按照年龄进行排序
           int result = o.getAge() - this.getAge();
           //次要条件,按照姓名排序。
           result = result == 0 ? o.getName().compareTo(this.getName()) : result;
           return result;
      }
    }

    测试类


    public class Test {
       public static void main(String[] args) {
           // 使用自然排序,要求键必须实现Comparable接口
           // TreeMap<Student,String> tm = new TreeMap<>();

           // 使用比较器排序
           TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
               @Override
               public int compare(Student o1, Student o2) {
                   int result = o1.getAge() - o2.getAge();
                   return (result== 0) ? o1.getName().compareTo(o2.getName()) : result;
              }
          });

           Student s1 = new Student(\"xiaohei\",23);
           Student s2 = new Student(\"dapang\",22);
           Student s3 = new Student(\"xiaomei\",22);

           tm.put(s1,\"江苏\");
           tm.put(s2,\"北京\");
           tm.put(s3,\"天津\");

           tm.forEach(
                  (Student key, String value)->{
                       System.out.println(key + \"---\" + value);
                  }
          );
      }
    }

14.可变参数

  • 可变参数介绍

    • JDK5新特性

  • 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 方法的参数类型已经确定,个数不确定,我们可以使用可变参数

  • 可变参数定义格式


    修饰符 返回值类型 方法名(数据类型… 变量名) { }
  • 可变参数的注意事项

    • 这里的变量其实是一个数组

    • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

  • 可变参数的基本使用


    /**
    * 需求:定义一个方法求N个数的和
    * 可变参数实现
    */
    public class MyVariableParameter3 {
       public static void main(String[] args) {

           int sum1 = getSum(1, 2);
           System.out.println(sum1);

           int sum2 = getSum(1, 2, 3);
           System.out.println(sum2);
      }

       public static int getSum(int... arr) {
           //说明可变数组 底层就是一个一维数组 这里是java的一个语法糖
           // 什么叫语法糖? 一种语法 ,这种语法对功能没有影响,主要方便程序员开发和阅读。
           // System.out.println(arr);//[I@10f87f48
           int sum = 0;
           for (int i = 0; i < arr.length; i++) {
               sum = sum + arr[i];
          }
           return sum;
      }
    }

15.创建不可变集合

  • 方法介绍

    • JDK9新特性

  • 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合

    • 这个集合不能添加,不能删除,不能修改

    • 但是可以结合集合的带参构造,实现集合的批量添加

  • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性

    • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中

  • 示例代码


    public class MyVariableParameter4 {
       public static void main(String[] args) {
           // method1();
           // method2();
           // method3();
           // method4();
      }

       private static void method4() {
           Map<String, String> map = Map.ofEntries(
                   Map.entry(\"zhangsan\", \"江苏\"),
                   Map.entry(\"lisi\", \"北京\"));
           System.out.println(map);
      }

       private static void method3() {
           Map<String, String> map = Map.of(\"zhangsan\", \"江苏\", \"lisi\", \"北京\", \"wangwu\", \"天津\");
           System.out.println(map);
      }

       private static void method2() {
           //传递的参数当中,不能存在重复的元素。
           Set<String> set = Set.of(\"a\", \"b\", \"c\", \"d\",\"a\");
           System.out.println(set);
      }

       private static void method1() {
           List<String> list = List.of(\"a\", \"b\", \"c\", \"d\");
           System.out.println(list);
           //list.add(\"Q\");
           //list.remove(\"a\");
           //list.set(0,\"A\");
           //System.out.println(list);

           //集合的批量添加。
           //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
           //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
           ArrayList<String> list3 = new ArrayList<>(List.of(\"a\", \"b\", \"c\", \"d\"));
           list3.add(\"1\");
           System.out.println(list3);
      }
    }

16.集合总结

 

  • 扩展一

    LinkedHashSet和LinkedHashMap: 可以实现去重并且存取有序的效果


    /**
    * LinkedHashSet和LinkedHashMap: 可以实现去重并且存取有序的效果
    */
    public class LinkedHashSetDemo {
       public static void main(String[] args) {
           HashSet<String> hashSet = new HashSet<>();
           hashSet.add(\"fff\");
           hashSet.add(\"aaa\");
           hashSet.add(\"bbb\");
           hashSet.add(\"ccc\");
           hashSet.add(\"ddd\");
           hashSet.add(\"ddd\");
           System.out.println(\"hashSet\" + hashSet);

           LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
           linkedHashSet.add(\"fff\");
           linkedHashSet.add(\"aaa\");
           linkedHashSet.add(\"bbb\");
           linkedHashSet.add(\"ccc\");
           linkedHashSet.add(\"ddd\");
           linkedHashSet.add(\"ddd\");
           System.out.println(\"linkedHashSet\" + linkedHashSet);

     HashMap<String, Integer> hashMap = new HashMap<>();
     hashMap.put(\"fff\", 1);
     hashMap.put(\"aaa\", 1);
     hashMap.put(\"bbb\", 1);
     hashMap.put(\"ccc\", 1);
     hashMap.put(\"ddd\", 1);
     System.out.println(\"hashMap\" + hashMap);


     LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
     linkedHashMap.put(\"fff\", 1);
     linkedHashMap.put(\"aaa\", 1);
     linkedHashMap.put(\"bbb\", 1);
     linkedHashMap.put(\"ccc\", 1);
     linkedHashMap.put(\"ddd\", 1);
     System.out.println(\"linkedHashMap\" + linkedHashMap);
}

}


 

- 扩展二

 // Java约定:如果二个对象equlas相等,那么hashcode也一定要相等,但是二个对象hashcode相等,equlas则不一定要相等。
 public class HashSetDemo2 {
     public static void main(String[] args) {
         Student s1 = new Student(\"张三\",23);
         Student s2 = new Student(\"张三\",23);
         Student s3 = new Student(\"李四\",24);

         //如果Student类没有重写hashcode方法,则根据地址值计算哈希值
         //如果重写了则一般根据属性值进行计算哈希值
         System.out.println(s1.hashCode());
         System.out.println(s2.hashCode());
         System.out.println(s3.hashCode());

         System.out.println(\"-----------------------------\");

         // Java约定:如果二个对象equlas相等,那么hashcode也一定要相等,
         // 但是二个对象hashcode相等,equlas则不一定要相等。
         //大部分情况不同的属性值计算出的哈希值都是不同的。但是也有例外
         Student s4 = new Student(\"重地\",23);
         Student s5 = new Student(\"通话\",23);
         System.out.println(s4.hashCode());  // 36561268
         System.out.println(s5.hashCode());  // 36561268
    }
}

 


来源:https://www.cnblogs.com/shiguangzheng/p/16621399.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » 集合总结

相关推荐

  • 暂无文章