Set
List是有序集合的根接口,Set是无序集合的根接口,无序也就意味着元素不重复。更严格地说,Set集合不包含一对元素e1和e2 ,使得e1.equals(e2) ,并且最多一个空元素。
使用Set存储的特点与List相反:元素无序、不可重复。常用的实现方式:HashSet、LinkedHashSet和TreeSet。
Set系列集合概述和特点
底层数据结构是哈希表
存取无序
不可以存储重复元素
没有索引,不能使用普通for循环遍历
set集合的基本应用
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);}}
方式2-增强for
//增强forfor (String str : s) {System.out.println(str);}
方式3lambda表达式
// Lambda表达式s.forEach((String str)-> System.out.println(str));
总结
HashSet集合概述和特点
底层数据结构是哈希表
存取无序
不可以存储重复元素
没有索引,不能使用普通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());//189568618System.out.println(s2.hashCode());//793589513*///不一样,所以我们要重写hashCode()// 2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样System.out.println("------------------");System.out.println(s1.hashCode());//1461067297System.out.println(s2.hashCode());//1461067297// 3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)//哈希碰撞System.out.println("abc".hashCode());//96354System.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方法
LinkedHashSet
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);}}
}
TreeSet
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);//使用增强forfor (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 + " ");}}
}
练习
@Overridepublic 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 + "}";}@Overridepublic 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;}
}