赞
踩
List是有序集合的根接口,Set是无序集合的根接口,无序也就意味着元素不重复。更严格地说,Set集合不包含一对元素e1和e2 ,使得e1.equals(e2) ,并且最多一个空元素。
使用Set存储的特点与List相反:元素无序、不可重复。常用的实现方式:HashSet、LinkedHashSet和TreeSet。
底层数据结构是哈希表
存取无序
不可以存储重复元素
没有索引,不能使用普通for循环遍历
- public static void main(String[] args) {
- Set<String> s=new HashSet<String>();
- boolean flag1= s.add("aaa");
- boolean flag2 = s.add("aaa");
- System.out.println(flag1);
- System.out.println(flag2);
- System.out.println(s);
- //如果当前元素是第一次添加,那么可以添加成功,返回true
- //如果当前元素是第二次添加,那么添加失败,返回false
- }
存储字符串并遍历
- public static void main(String[] args) {
- Set<String> s=new HashSet<String>();
- s.add("张三");
- s.add("李四");
- //迭代器
- Iterator<String> it = s.iterator();
- while(it.hasNext()){
- String str = it.next();
- System.out.println(str);
- }
-
-
- }
-
- //增强for
- for (String str : s) {
- System.out.println(str);
- }
- // Lambda表达式
- s.forEach((String str)-> System.out.println(str));
总结
底层数据结构是哈希表
存取无序
不可以存储重复元素
没有索引,不能使用普通for循环遍历
哈希值简介
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值
哈希值的特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
- package set;
- /*
- 哈希值:
- 对象的整数表现形式
- 1. 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
- 2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
- 3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
- */
- public class demo3 {
- public static void main(String[] args) {
-
- // 1. 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
- Student s1 = new Student("zhangsan",18);
- Student s2 = new Student("zhangsan",18);
- /* System.out.println(s1.hashCode());//189568618
- System.out.println(s2.hashCode());//793589513*/
- //不一样,所以我们要重写hashCode()
- // 2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样
- System.out.println("------------------");
- System.out.println(s1.hashCode());//1461067297
- System.out.println(s2.hashCode());//1461067297
- // 3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
- //哈希碰撞
- System.out.println("abc".hashCode());//96354
- System.out.println("acD".hashCode());//96354
- }
- }
- package lx;
-
- import java.util.HashSet;
-
- public class demo1 {
- public static void main(String[] args) {
- Student s1 = new Student("张三", 8);
- Student s2 = new Student("张三", 8);
- Student s3 = new Student("李四", 18);
- Student s4 = new Student("王五", 17);
- HashSet<Student> set = new HashSet<Student>();
- set.add(s1);
- set.add(s2);
- set.add(s3);
- set.add(s4);
- //重写hashCode方法就可以去重复的对象
- //因为重写hashCode方法,比的是属性值,属性值一样,哈希值一样,所以添加不成功
- //不重写比的是地址值,创建出来的对象地址值永远不一样,所以哈希值不一样,所以添加成功
- //如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样
- //重写equals方法也一样 比的也是地址值,不是属性值
- for (Student student : set) {
- System.out.println(student);
- }
- }
- }
注意像String Integer类型的,Java已经在底层重写好了HashSet和equals方法
- package LinkedHashSet;
-
- import lx.Student;
-
-
- import java.util.HashSet;
- import java.util.LinkedHashSet;
-
- public class demo1 {
- public static void main(String[] args) {
-
- Student s1 = new Student("张三", 8);
-
-
- Student s2 = new Student("张三", 8);
- Student s3 = new Student("李四", 18);
- Student s4 = new Student("王五", 17);
- LinkedHashSet<Student> set = new LinkedHashSet<Student>();
- set.add(s3);
- set.add(s1);
- set.add(s3);
- set.add(s4);
- //LinkedHashSet的存和去顺序一样
- for (Student student : set) {
-
- System.out.println(student);
- }
-
- }
- }
- package TreeSet;
-
- import java.util.TreeSet;
-
- public class demo1 {
- public static void main(String[] args) {
- //利用TreeSet对整数进行排序
- //默认升序
- TreeSet<Integer> ts = new TreeSet<>();
- //添加元素
- ts.add(4);
- ts.add(2);
- ts.add(5);
- ts.add(8);
- ts.add(1);
- //使用增强for
- for (Integer t : ts) {
- System.out.print(t + " ");
- }
-
- }
- }
- package TreeSet;
-
- import java.util.TreeSet;
-
- public class demo2 {
- public static void main(String[] args) {
- //利用TreeSet对String类型进行排序
- TreeSet<String> ts = new TreeSet<>();
- ts.add("va");
- ts.add("aaa");
- ts.add("ha");
- ts.add("aba");
- ts.add("acd");
- for (String t : ts) {
- System.out.print(t + " ");
- }
- }
- }
- @Override
- public int compareTo(Student o) {
- //只看年龄按照升序排序
- int tmp=this.getAge() - o.getAge();
- tmp= tmp==0?this.getName().compareTo(o.getName()):tmp;
- return tmp;
- }
- package TreeSet;
-
- import javax.print.DocFlavor;
- import java.util.TreeSet;
- import java.util.function.Consumer;
-
- public class demo3 {
- public static void main(String[] args) {
- //利用TreeSet对学生类型进行排序
- TreeSet<Student> ts = new TreeSet<>();
- //要求: 按照学生的年龄进行排序
- //同年按照姓名字母排序
- //同姓名,同年龄认为同一个人
- Student s1 = new Student("zhangsan", 18);
- Student s2 = new Student("lisi", 19);
- Student s3 = new Student("wangwu", 19);
- ts.add(s2);
- ts.add(s3);
- ts.add(s1);
- System.out.println(ts);
- //方式一:默认的排序方式,Student实现一个接口(comparable接口)重写里面的抽象方法
- //再指定比较规则
- //hashCode和equals方法跟哈希表有关
- //TreeSet底层红黑树有关
- //所以不需要重写hashCode和equals方法
- }
- }
- package TreeSet;
-
- import java.util.Comparator;
- import java.util.TreeSet;
-
- public class demo4 {
- public static void main(String[] args) {
- //方法二:比较器排序
- //1.创建集合
- //2.o1表示当前要添加的元素
- //3.o2表示已经在红黑树存在的元素
- //返回值规则跟之前一样
- TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
- @Override
- /*
- 需求:请自行选择比较器排序和自然排序两种方式;
- 要求:存入四个字符串, “c”, “ab”, “df”, “qwer”
- 按照长度排序,如果一样长则按照首字母排序
-
- 采取第二种排序方式:比较器排序
- */
- public int compare(String o1, String o2) {
- //按照长度来
- int tmp = o1.length() - o2.length();
- //如果一样长则按照首字母排序
- tmp = tmp == 0 ? o1.compareTo(o2) : tmp;
- return tmp;
- }
- });
- //2.添加元素
- ts.add("c");
- ts.add("ab");
- ts.add("df");
- ts.add("qwer");
- System.out.println(ts);
- }
- }
- package lx2;
-
- import java.util.TreeSet;
-
- /* 需求:创建5个学生对象
- 属性:(姓名,年龄,语文成绩,数学成绩,英语成绩),
- 按照总分从高到低输出到控制台
- 如果总分一样,按照语文成绩排
- 如果语文一样,按照数学成绩排
- 如果数学成绩一样,按照英语成绩排
- 如果英文成绩一样,按照年龄排
- 如果年龄一样,按照姓名的字母顺序排
- 如果都一样,认为是同一个学生,不存。
- 第一种:默认排序/自然排序
- 第二种:比较器排序
-
- 默认情况下,用第一种排序方式,如果第一种不能满足当前的需求,采取第二种方式。
-
-
- 课堂练习:
- 要求:在遍历集合的时候,我想看到总分。
-
- */
- public class demo1 {
- public static void main(String[] args) {
- //1.创建学生对象
- Student s1 = new Student("zhangsan", 23, 90, 99, 50);
- Student s2 = new Student("lisi", 24, 90, 98, 50);
- Student s3 = new Student("wangwu", 25, 95, 100, 30);
- Student s4 = new Student("zhaoliu", 26, 60, 99, 70);
- Student s5 = new Student("qianqi", 26, 70, 80, 70);
- TreeSet<Student> st=new TreeSet<>();
- st.add(s1);
- st.add(s2);
- st.add(s3);
- st.add(s4);
- st.add(s5);
- for (Student student : st) {
- System.out.println(student);
- }
- }
- }
- package lx2;
-
- //第一种:默认排序/自然排序
- public class Student implements Comparable<Student> {
- private String name;
- private int age;
- //语文成绩
- private int chinese;
- //数学成绩
- private int math;
- //英语成绩
- private int english;
-
- public Student() {
- }
-
- public Student(String name, int age, int chinese, int math, int english) {
- this.name = name;
- this.age = age;
- this.chinese = chinese;
- this.math = math;
- this.english = english;
- }
-
- /**
- * 获取
- *
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- *
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- *
- * @return age
- */
- public int getAge() {
- return age;
- }
-
- /**
- * 设置
- *
- * @param age
- */
- public void setAge(int age) {
- this.age = age;
- }
-
- /**
- * 获取
- *
- * @return chinese
- */
- public int getChinese() {
- return chinese;
- }
-
- /**
- * 设置
- *
- * @param chinese
- */
- public void setChinese(int chinese) {
- this.chinese = chinese;
- }
-
- /**
- * 获取
- *
- * @return math
- */
- public int getMath() {
- return math;
- }
-
- /**
- * 设置
- *
- * @param math
- */
- public void setMath(int math) {
- this.math = math;
- }
-
- /**
- * 获取
- *
- * @return english
- */
- public int getEnglish() {
- return english;
- }
-
- /**
- * 设置
- *
- * @param english
- */
- public void setEnglish(int english) {
- this.english = english;
- }
-
- public String toString() {
- return "Student{name = " + name + ", age = " + age + ", chinese = " + chinese + ", math = " + math + ", english = " + english + "}";
- }
-
- @Override
- public int compareTo(Student o) {
- /* 按照总分从高到低输出到控制台
- 如果总分一样,按照语文成绩排
- 如果语文一样,按照数学成绩排
- 如果数学成绩一样,按照英语成绩排
- 如果英文成绩一样,按照年龄排
- 如果年龄一样,按照姓名的字母顺序排
- 如果都一样,认为是同一个学生,不存。*/
- int sum1 = this.getChinese() + this.getMath() + this.getEnglish();
- int sum2=o.getChinese() + o.getMath() + o.getEnglish();
- int tmp = sum2-sum1;
- // 如果总分一样,按照语文成绩排
- tmp = tmp == 0 ? this.getChinese() - o.getChinese() : tmp;
- // 如果语文一样,按照数学成绩排
- tmp = tmp == 0 ? this.getMath() - o.getMath() : tmp;
- //如果数学成绩一样,按照英语成绩排
- tmp = tmp == 0 ? this.getEnglish() - o.getEnglish() : tmp;
- //如果英文成绩一样,按照年龄排
- tmp = tmp == 0 ? this.getAge() - o.getAge() : tmp;
- // 如果年龄一样,按照姓名的字母顺序排
- tmp = tmp == 0 ? this.getName().compareTo(o.getName()) : tmp;
-
-
- return tmp;
- }
- }
- public class test {
- public static void main(String[] args) {
- TreeSet<String> ts = new TreeSet<>((o1, o2) -> o1.compareTo(o2));
- ts.add("c");
- ts.add("ab");
- ts.add("df");
- ts.add("qwer");
- System.out.println(ts);//默认是通过Stirng排序方法,也就是说通过首字母排序的方法来的,不是根据长度来的
- }
- }
如果使用默认的排序方法,则不能满足需求,可以使用第二种排序方法,并定义规矩进行重写
排序的原理图:
总结
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。