1. HashSet存储字符串并遍历

  • Set集合概述及特点

    • 一个不包含重复元素的Collection。

    • set不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个null元素。
    • Set接口没有特殊方法,完全继承Collection接口中的方法。
    • 只要注意如何保证Set集合的元素唯一
    • 无索引,不可以重复,存取不一致
  • 案例演示

    • HashSet存储字符串并遍历

    • package com.heima.set;
      
      import java.util.HashSet;
      
      public class Demo1_HashSet {
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              HashSet<String> hs = new HashSet<>();
              hs.add("a");
              hs.add("b");
              boolean b1 = hs.add("a");
              System.out.println(b1); //输出false 当存储不成功的时候,返回false
              
              for (String string : hs) {
                  System.out.println(string);
              }
          }
      
      }
      View Code

 

2. HashSet存储自定义对象保证元素唯一性

  • 案例演示

    • 存储自定义对象,并保证元素唯一性。

    • package com.heima.set;
      
      import java.util.HashSet;
      
      import com.heima.bean.Person;
      
      public class Demo2_HashSet {
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              HashSet<Person> hs = new HashSet<>(); 
              hs.add(new Person("张三", 23)); 
              hs.add(new Person("张三", 23)); 
              hs.add(new Person("李四", 23)); 
              hs.add(new Person("李四", 23)); 
              hs.add(new Person("王五", 23)); 
              hs.add(new Person("赵六", 23));
              
              for (Person person : hs) {
                  System.out.println(person);
              }
              
          }
      
      }
      View Code
  • 重写equals()方法

    • package com.heima.bean;
      
      public class Person {
          private String name;
          private int age;
          public Person() {
              super();
              
          }
          public Person(String name, int age) {
              super();
              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 "Person [name=" + name + ", age=" + age + "]";
          }
          @Override
          public boolean equals(Object obj) {
              Person p = (Person)obj;
              return this.name.equals(p.getName()) && this.age == p.getAge();
              //return super.equals(obj);
          }
          
          
      }
      重写equals方法后
    • 重写euqals()方法后,并不能保证自定义对象在集合中唯一性
  • 重写hashCode() 和 equals()方法
    • package com.heima.bean;
      
      public class Person {
          private String name;
          private int age;
          public Person() {
              super();
              
          }
          public Person(String name, int age) {
              super();
              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 "Person [name=" + name + ", age=" + age + "]";
          }
          /*@Override
          public boolean equals(Object obj) {
              Person p = (Person)obj;
              System.out.println("验证equals是否执行");
              return this.name.equals(p.getName()) && this.age == p.getAge();
              
          }
          @Override
          public int hashCode() {
              // 第一种方法:hashCode 返回固定值,每次自定义对象都要与生成的第一个占据了固定值位置的对象比较
              // 由于hashCode相等,继而去调用equals方法。
      //        return 10;
              
              // 第二种方法:String对象的hashCode值和 数值 ,减少equals比较调用次数。
      //        return name.hashCode() + age;
              
              // 第三种方法:优化:
      //        final int NUM = 38;
      //        return name.hashCode() * NUM + age;
      }
      */        
              // 第四种方法:开发时常用,alt+shift+s 自动生成
          @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;
              Person other = (Person) 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;
          }
              
          
          
          
          
      }
      View Code
  • 代码优化

    • 为了减少比较,优化hashCode()代码写法。

    • 最终版就是自动生成即可。

 

3. HashSet如何保证元素唯一性的原理

  • HashSet原理

    • 我们使用Set集合都是需要去掉重复元素的,如果在存储的时候逐个equals()比较,,效率较低,哈希算法提高了去重复的效率,,降低了使用equals()方法的次数

    • 当HashSet调用add()方法存储对象的时候,,先调用对象的hashCode()方法得到一个哈希值,,然后在集合中查找是否有哈希值相同的对象

      • 如果没有哈希值相同的对象就直接存入集合

      • 如果有哈希值相同的对象,,就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存

  • 将自定义类的对象存入HashSet去重复

    • 类中必须重写hashCode()和equals()方法

    • hashCode():属性相同的对象返回值必须相同,,属性不同的返回值尽量不同(提高效率)

    • equals()::属性相同返回true, 属性不同返回false,返回false的时候存储

 

4. LinkedHashSet的概述和使用

  • LinkedHashSet的特点

    • 保证存取顺序一致
    • LinkedHashSet底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象
    • 因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样
  • 案例演示

    • package com.heima.set;
      
      import java.util.LinkedHashSet;
      
      public class Demo3_LinkedHashSet {
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              LinkedHashSet<String> lhs = new LinkedHashSet<>();
              lhs.add("a");
              lhs.add("b");
              lhs.add("b");
              lhs.add("c");
              lhs.add("b");
              lhs.add("a");
              
              for (String string : lhs) {
                  System.out.println(string);  // 输出a b c
              }
          }
      
      }
      View Code

       


5. 
练习

  • 产生10个1-20之间的随机数要求随机数不能重复

  • 案例演示

    • 需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。

    • package com.heima.test;
      
      import java.util.HashSet;
      import java.util.Random;
      
      public class Test1 {
      
          /**
           编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。
           */
          public static void main(String[] args) {
              HashSet<Integer> hs = new HashSet<>();   //创建集合对象 
              Random r = new Random(); //创建随机数对象
              while(hs.size() < 10) {
                  int num = r.nextInt(20) + 1;
                  hs.add(num);
              }
                      
              for (Integer integer : hs) {
                  System.out.println(integer);
              }
              
          }
      
      }
      View Code

       

  • 使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符

    • package com.heima.test;
      
      import java.util.HashSet;
      import java.util.Scanner;
      
      public class Test2 {
      
          /**
           使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符
           */
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入一行字符串:");
              String line = sc.nextLine();
              char[] arr = line.toCharArray(); // 将字符串转换成字符数组
              
              HashSet<Character> hs = new HashSet<>();
              for (Character character : arr) {
                  hs.add(character);
              }
              
              for (Character character : hs) {
                  System.out.println(character);
              }
          
          }
      
      }
      View Code
  • 将集合中的重复元素去掉

    • package com.heima.test;
      
      import java.util.ArrayList;
      import java.util.LinkedHashSet;
      import java.util.List;
      
      public class Test3 {
          /*
           * 将集合中的重复元素去掉
           */
          public static void main(String[] args) {
              ArrayList<String> list = new ArrayList<>(); 
              list.add("a"); 
              list.add("a"); 
              list.add("a"); 
              list.add("b"); 
              list.add("b"); 
              list.add("b"); 
              list.add("b"); 
              list.add("c"); 
              list.add("c"); 
              list.add("c"); 
              list.add("c");
      
              System.out.println(list);
              System.out.println("去除重复后:");
              getSingle(list);
              System.out.println(list);
          }
          
          /*
           * 将集合中的重复元素去掉
           * 1,void
           * 2,List<String> list
           */
          
          public static void getSingle(List<String> list) {
              LinkedHashSet<String> lhs = new LinkedHashSet<>();
              lhs.addAll(list);           //将list集合中的所有元素添加到lhs
              list.clear();               //清空原集合
              list.addAll(lhs);         //将去除重复的元素添回到list中
          }
          
      }
      View Code

       

 

6. TreeSet存储Integer类型的元素并遍历

  • 案例演示

    • TreeSet存储Integer类型的元素并遍历

    • package com.heima.set;
      
      import java.util.TreeSet;
      
      public class Demo4_TreeSet {
      
          /**
          TreeSet集合是用来对元素进行排序的,也可以保证元素的唯一性
           */
          public static void main(String[] args) {
              TreeSet<Integer> ts = new TreeSet<>();
              ts.add(4);
              ts.add(1);
              ts.add(2);
              ts.add(3);
              
              System.out.println(ts);  // 输出[1,2,3,4]
              
          }
      
      }
      View Code

       

 

7. TreeSet存储自定义对象

  • 案例演示

    • 存储Person对象

    • package com.heima.bean;
      
      public class Person implements Comparable<Person>{
          private String name;
          private int age;
          public Person() {
              super();
              
          }
          public Person(String name, int age) {
              super();
              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 "Person [name=" + name + ", age=" + age + "]";
          }
          
          //开发时常用,alt+shift+s 自动生成
          @Override
          public int hashCode() {
              final int prime = 31;
              int result = 1;
              result = prime * result + age;
              result = prime * result + ((name == null) ? 0 : name.hashCode());
              System.out.println(result);
              return result;
          }
          @Override
          public boolean equals(Object obj) {
              if (this == obj)
                  return true;
              if (obj == null)
                  return false;
              if (getClass() != obj.getClass())
                  return false;
              Person other = (Person) 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;
          }
          // control + 1, 点击自动生成重写compareTo方法的样式
          @Override
          public int compareTo(Person o) {
              
              return -1;
          }
              
          
          
          
          
      }
      Person类Comparable接口

       

    • package com.heima.set;
      
      import java.util.TreeSet;
      
      import com.heima.bean.Person;
      
      public class Demo5_TreeSet {
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              TreeSet<Person> ts = new TreeSet<>();
              ts.add(new Person("Ann",22));
              ts.add(new Person("Bill",23));
              ts.add(new Person("Carolle",21));
              ts.add(new Person("Dell",28));
              
              System.out.println(ts); 
              // 报错,ClassCastException
              // Person类接入 Comparable接口,重写compareTo方法后,按照规则输出
              
              
          }
      
      }
      View Code

       

  • TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一
  • 当compareTo方法返回0的时候,集合中只有一个元素
  • 当compareTo方法返回 正整数 的时候,集合会怎么存就怎么取(存取顺序一致)
  • 当compareTo方法返回 负整数 的时候,按照倒序返回

 

8. TreeSet保证元素唯一和自然排序的原理和图解

  • 画图演示

    • TreeSet保证元素唯一和自然排序的原理和图解

    •  

    • 主要条件age,次要条件name
      • @Override
            public int compareTo(Person o) {
                
                int num = this.age - o.age;
                return num == 0 ? this.name.compareTo(o.name): num;
            }
                

         

9. TreeSet存储自定义对象并遍历练习

  • TreeSet存储自定义对象并遍历练习1(按照姓名排序)

    • @Override
          public int compareTo(Person o) {
              int num = this.name.compareTo(o.name);
              return num == 0 ? this.age - o.age : num;
              }

       

  • TreeSet存储自定义对象并遍历练习2(按照姓名的长度排序)

    • @Override
          public int compareTo(Person o) {
              int length = this.name.length() - o.name.length();
              int num = length == 0 ? this.name.compareTo(o.name) : length;
              return num == 0 ? this.age - o.age : num;
              
          }

       

10. TreeSet保证元素唯一和比较器排序的原理及代码实现

  • 案例演示

    • TreeSet保证元素唯一和比较器排序的原理及代码实现

    • package com.heima.set;
      
      import java.util.Comparator;
      import java.util.TreeSet;
      
      public class Demo6_TreeSet {
      
          /**
           TreeSet保证元素唯一和比较器排序的原理及代码实现
           */
          public static void main(String[] args) {
              TreeSet<String> ts = new TreeSet<>(new CompareByLen()); // Comparator<String> cp = new CompareByLen();
              ts.add("aaaaaaaaaaaaaaaa");
              ts.add("wc");
              ts.add("who");
              ts.add("MCGA");
              ts.add("Make China Great Again");
              ts.add("Trump");
              ts.add("piapiapia");
              
              for (String string : ts) {
                  System.out.println(string);
              }
              
          }
      
      }
      
      class CompareByLen implements Comparator<String> {
      
          @Override
          public int compare(String s1, String s2) {
              // 按照字符串的长度进行比较
              int length = s1.length() - s2.length();
              return length == 0 ? s1.compareTo(s2) : length;
          }
          
      }
      View Code
  • TreeSet原理
    • 特点

      • TreeSet是用来排序的,可以指定一个顺序, 对象存入之后会按照指定的顺序排列

    • 使用方式

      • 自然顺序(Comparable)

        • TreeSet类的add()方法中会把存入的对象提升为Comparable类型

        • 调用对象的compareTo()方法和集合中的对象比较

        • 根据compareTo()方法返回的结果进行存储

      • 比较器顺序(Comparator)

        • 创建TreeSet的时候可以制定 一个Comparator

        • 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序

        • add()方法内部会自动调用Comparator接口中compare()方法排序

        • 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

      • 两种方式的区别

        • TreeSet构造函数什么都不传,默认按照类中Comparable的顺序(没有就报错ClassCastException)

        • TreeSet如果传入Comparator,就优先按照Comparator

11. 练习

  • 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复

    • package com.heima.test;
      
      import java.util.ArrayList;
      import java.util.Comparator;
      import java.util.List;
      import java.util.TreeSet;
      
      public class Test5 {
      
          /**
          在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
           */
          public static void main(String[] args) {
              ArrayList<String> list = new ArrayList<>(); 
              list.add("ccc"); 
              list.add("ccc"); 
              list.add("aaa"); 
              list.add("aaa"); 
              list.add("bbb"); 
              list.add("ddd");
              list.add("ddd");
      
              sort(list);
              System.out.println(list);
          }
          
          /*
           * 定义方法,排序并保留重复
           * 分析:
           * 1. 创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用 比较器
           * 2. 将list集合中所有的元素添加到TreeSet集合中,对其排序,保留重复
           * 3. 清空list集合
           * 4. 将TreeSet集合中排好序的元素添加到list中
          */
          
          public static void sort(List<String> list) {
              //1. 创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用 比较器
              TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
      
                  @Override
                  public int compare(String s1, String s2) {  // 这边使用了Comparator的匿名内部类的方法,重写了compare方法
                      int num = s1.compareTo(s2);  // 比较字符串顺序为主要条件
                      return num == 0 ? 1 : num;  // 保留重复数据
                  } });
              
              // 2. 将list集合中所有的元素添加到TreeSet集合中,对其排序,保留重复
              ts.addAll(list);
              
              // 3. 清空list集合
              list.clear();
              
              // 4. 将TreeSet集合中排好序的元素添加到list中
              list.addAll(ts);
          }
      }
      View Code
  • 从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt

    • package com.heima.test;
      
      import java.util.ArrayList;
      import java.util.Comparator;
      import java.util.Scanner;
      import java.util.TreeSet;
      
      public class Test6 {
      
          /**
           从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
           */
          public static void main(String[] args) {
              /*
               * 1. 键盘录入字符串,Scanner
               * 2. 将字符串转换为字符数组
               * 3. 定义TreeSet集合,传入比较器对字符排序并保留重复
               * 4. 遍历字符数组,将每一个字符存储在TreeSet集合中
               * 5. 遍历TreeSet集合,打印每一个字符
               */
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入一行字符串:");
              
              String line = sc.nextLine();
              char[] arr = line.toCharArray();
              
              ArrayList<String> list = new ArrayList<>();
              list.add(line);
              
              System.out.println(list);
              
              TreeSet<Character> ts = new TreeSet<>(new Comparator<Character>() {
      
                  @Override
                  public int compare(Character c1, Character c2) {
                      int num = c1.compareTo(c2);
                      return num == 0 ? 1 : num;
                  }
              });
              
              for (char c : arr) {
                  ts.add(c);
              }
              
              for (Character ch : ts) {
                  System.out.print(ch);
              }
              
          }
      
      }
      View Code
  • 程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印

    • package com.heima.test;
      
      import java.util.Comparator;
      import java.util.Scanner;
      import java.util.TreeSet;
      
      public class Test7 {
      
          /**
           程序启动后,可以从键盘输入接收多个整数,直到输入quit时结束输入。
           把所有输入的整数倒序排列打印
           */
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入整数:");
              
              TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {
      
                  @Override
                  public int compare(Integer i1, Integer i2) {
                      int num = i2.compareTo(i1);  //自动拆箱
                      return num==0 ? 1: num;
                  }
              }
                      );
              
              while(true) {
                  String line = sc.nextLine();
                  if("quit".equals(line))  //如果字符串常量和变量比较,常量放前面,这样不会出现空指针异常,变量里面可能存储null
                      break;
                  try {
                      int num = Integer.parseInt(line);  //将数字字符串转换成数字
                      ts.add(num);
                      
                  } catch (Exception e) {
                      System.out.println("您录入的数据有误,请输入一个整数");
                  }
              }
              
              
              for (Integer integer : ts) {
                  System.out.println(integer);
              }
              
          }
      
      }
      View Code
  • 键盘录入学生信息按照总分排序后输出在控制台

    • 需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。

    • package com.heima.test;
      
      import java.util.Comparator;
      import java.util.Scanner;
      import java.util.TreeSet;
      
      import com.heima.bean.Student;
      
      public class Test8 {
      
          /**
           需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
           分析:
           1. 定义一个学生类
               成员变量:姓名,语文成绩,数学成绩,英语成绩,总成绩
               成员方法:
                   空参构造
                   有参构造(参数:姓名,语文成绩,数学成绩,英语成绩)
                   toString方法:遍历集合中的Student对象,显示属性值
           2. 键盘录入Scanner
           3. 创建TreeSet集合对象,引入比较器,按总成绩从高到低排序
           4. 录入5个学生,所以集合中的学生个数为判断条件,如果size是小于5就进行存储
           5. 将录入的字符串切割,用逗号切割,会返回一个字符串数组,将字符串数组中从第二个元素转换成int数组
           6. 将转换后的结果封装成Studeng对象,将Studeng添加到TreeSet集合中
           7. 遍历TreeSet集合,打印每一个Student对象
      
           */
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩)");
      
              TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>(
                      ) {
      
                  @Override
                  public int compare(Student s1, Student s2) {
                      int num = s2.getSum() - s1.getSum();//根据学生的总成绩降序排列
                      return num==0 ? 1 : num;
                  }
              });
      
              while(ts.size() < 5) {
                  String line = sc.nextLine();
                  try {
                      String[] arr = line.split(",");
                      int chinese = Integer.parseInt(arr[1]);
                      int math = Integer.parseInt(arr[2]);
                      int english = Integer.parseInt(arr[3]);
                      ts.add(new Student(arr[0],chinese,math,english));
                  } catch (Exception e) {
                      System.out.println("录入格式有误,输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩)");
                  }
              }
      
              System.out.println("排序后的学生成绩是:");
              for (Student student : ts) {
                  System.out.println(student);
              }
      
          }
      
      }
      View Code

        

12. List和Set在for循环,迭代器,增强for循环的小结

  • List

    • 普通for循环, 使用get()逐个获取

    • 调用iterator()方法得到Iterator,使用hasNext()和next()方法

    • 增强for循环,,只要可以使用Iterator的类都可以用

    • Vector集合可以使用Enumeration的hasMoreElements()和nextElement()方法

  • Set

    • 调用iterator()方法得到Iterator,使用hasNext()和next()方法

    • 增强for循环, 只要可以使用Iterator的类都可以用

  • 普通for循环、迭代器、增强for循环是否可以在遍历的过程中删除

posted on 2020-05-26 16:49  Zoe233  阅读(196)  评论(0编辑  收藏  举报