Set集合
set集合概述:
一个不包含重复元素的 collection
set集合特点:
元素唯一,不允许重复
Set集合的子类:
HashSet
HashSet底层数据结构:
哈希表(JDK1.7 数组+链表 JDK1.8 优化 数组+链表+红黑树)
特点:
元素无序(存取元素的顺序不一致)且唯一(元素不允许重复)
HashSet怎么保证元素的唯一性?
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的
hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。HashSet 集合判断两个
元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也
相等。HashSet集合保证元素的唯一性,是靠元素重新hashCode和equals()方法来保证的,如果元素
不重写,则无法保证元素的 唯一性。
HashSet唯一性图解:
代码举例说明:
特点:元素无序且唯一
public class MyTest {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("aaaa");
set.add("aaaa");
set.add("bbb");
set.add("ccc");
for (String s : set) {
System.out.println(s);//运行结果:aaaa ccc bbb 元素唯一但是无序
}
System.out.println("==========================");
HashSet<Integer> set2 = new HashSet<>();
set2.add(200);
set2.add(200);
set2.add(200);
set2.add(100);
set2.add(300);
System.out.println(set2);//运行结果 300 100 200
}
}
HashSet 底层用的HashMap 这个集合来存的。HashMap中通过计算输入的对象的键值得出一个hash地址值,当你想要存储该对象时,会调用equals方法,进行比较,如果地址中没有该对象,就会将该对象存入,如果有该对对象将不在进行存入,从而确保了元素的唯一性。合理的重写 hashCode 方法是为了减少 equals() 方法的调用次数,也就是说为了减少碰撞。
自定义一个学生类进行举例:
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;
}
//重写hashCode和equals()方法
@Override
public boolean equals(Object o) {
System.out.println("equals方法"+this+"==="+o);
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return this.name.hashCode()+this.age*11;//当姓名一致时,年龄不同,如果hashCode方法重写不得当,可能会将两个不同的对象判断为一个对象,因此在这里需要进行合理的重写,区分出两个不同的对象。
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MyTest {
public static void main(String[] args) {
//HashSet 底层用的HashMap 这个集合来存的
//合理的重写hashCode方法,为了减少equals()方法的调用次数,也就是说为了减少碰撞。
HashSet<Student> set = new HashSet<>();
set.add(new Student("张三",23));
set.add(new Student("张三", 23));
set.add(new Student("张三", 24));
set.add(new Student("李四", 24));
set.add(new Student("王五", 25));
for (Student student : set) {
System.out.println(student);
}
}
}
运行结果:
Student{name='张三', age=23}
Student{name='李四', age=24}
Student{name='王五', age=25}
Student{name='张三', age=24} 元素唯一 且无序
LinkedHashSet
**LinkedHashSet底层数据结构:**底层数据结构是链表+哈希表
**特点:**链表保证元素有序,哈希表保证元素唯一
代码举例:
public class MyTest {
public static void main(String[] args) {
LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(100);
linkedHashSet.add(100);
linkedHashSet.add(100);
linkedHashSet.add(200);
linkedHashSet.add(300);
linkedHashSet.add(400);
//增强for循环
for (Integer integer : linkedHashSet) {
System.out.println(integer);
}
}
}
运行结果:
100
200
300
400
TreeSet
**TreeSet底层数据结构:**底层数据结构是二叉树
**特点:**元素唯一,且能对元素进行排序
TreeSet排序方法:自然排序和使用比较器排序
(注意:使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现
Comparable接口 否则无法进行自然排序)
TreeSet保证唯一性图解:
代码举例:
public class MyTest {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(20);
treeSet.add(18);
treeSet.add(23);
treeSet.add(22);
treeSet.add(17);
treeSet.add(24);
treeSet.add(19);
treeSet.add(18);
treeSet.add(24);
for (Integer integer : treeSet) {
System.out.println(integer);
}
}
}
运行结果:
17
18
19
20
22
23
24
TreeSet排序:自然排序
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 +
'}';
}
//使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现Comparable接口 否则无法进行自然排序
@Override
public int compareTo(Student s) {
//根据年龄大小来排序
/* int num=this.age - s.age;
//如果年龄相同,并不能说明他们是同一个对象,还得比较姓名是否相同。
int num2=num==0?this.name.compareTo(s.name):num;
return num2;*/
/*按照姓名的长度来排序*/
int num =this.name.length()-s.name.length();
//当姓名的长度一样,不能说明是同一个对象,还得比较姓名内容
int num2=num==0?this.name.compareTo(s.name):num;
//当姓名长度,姓名内容一样,也不能说明是同一个对象,还得比较年龄是否相同
int num3=num2==0?this.age-s.age:num2;
return num3;
}
}
public class MyTest2 {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("张庭aaaaaadfdfdfa",23));
treeSet.add(new Student("张庭2aaa", 23));
treeSet.add(new Student("张柏芝aaa", 18));
treeSet.add(new Student("张惠妹aaa", 20));
treeSet.add(new Student("张惠妹", 20));
treeSet.add(new Student("张惠妹", 22));
treeSet.add(new Student("张余生", 20));
treeSet.add(new Student("张曼玉aaaaaaa", 24));
treeSet.add(new Student("林青霞aaaaaaaaaa", 26));
for (Student student : treeSet) {
System.out.println(student.getName()+"=="+student.getAge());
}
}
}
运行结果:
张余生==20
张惠妹==20
张惠妹==22
张庭2aaa==23
张惠妹aaa==20
张柏芝aaa==18
张曼玉aaaaaaa==24
林青霞aaaaaaaaaa==26
张庭aaaaaadfdfdfa==23
TreeSet排序:比较器排序
TreeSet(Comparator < ? super E > comparator)构造一个新的空 TreeSet,它根据指定比较器进行排
序。
public class MyTest {
public static void main(String[] args) {
//TreeSet 排序方式2:比较器排序 ,使用有参构造。
TreeSet<Student> treeSet = new TreeSet<>(new MyComparator());
treeSet.add(new Student("张庭", 23));
treeSet.add(new Student("张庭", 22));
treeSet.add(new Student("张惠妹", 20));
treeSet.add(new Student("张惠妹", 22));
treeSet.add(new Student("张余生", 20));
treeSet.add(new Student("张曼玉", 24));
treeSet.add(new Student("林青霞", 26));
for (Student student : treeSet) {
System.out.println(student.getName() + "==" + student.getAge());
}
}
}
class MyComparator implements Comparator<Student>{
@Override
public int compare(Student s1, Student s2) {
//System.out.println("比较的方法调用了");
//安装年龄大小 来排序
int num= s1.getAge()-s2.getAge();
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
}
//比较器作为匿名内部类进行排序
public class MyTest1 {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});
treeSet.add(new Student("张庭", 23));
treeSet.add(new Student("张庭", 22));
treeSet.add(new Student("张惠妹", 20));
treeSet.add(new Student("张惠妹", 22));
treeSet.add(new Student("张余生", 20));
treeSet.add(new Student("张曼玉", 24));
treeSet.add(new Student("林青霞", 26));
for (Student student : treeSet) {
System.out.println(student.getName() + "==" + student.getAge());
}
}
}
//学生类
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
应用案例:
1.获取10个1至20的随机数,要求随机数不能重复
public class MyTest {
public static void main(String[] args) {
Random random = new Random();
LinkedHashSet<Integer> set = new LinkedHashSet<>();
while (set.size()<10){
int num = random.nextInt(20) + 1;
set.add(num);
}
System.out.println(set);
}
}
2.键盘录入学生信息按照总分排序后输出在控制台
public class MyTest {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num= s1.getTotalScore()-s2.getTotalScore();
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
return -num2;
}
});
for (int i = 1; i <= 3; i++) {
Student student = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入第"+i+"个学生的姓名");
String name = sc.nextLine();
student.setName(name);
System.out.println("请输入第" + i + "个学生的语文成绩");
int yw = sc.nextInt();
student.setChineseScore(yw);
System.out.println("请输入第" + i + "个学生的数学成绩");
int sx= sc.nextInt();
student.setMathScore(sx);
System.out.println("请输入第" + i + "个学生的英语成绩");
int yy = sc.nextInt();
student.setEnglishScore(yy);
//把学生对象添加到集合里面
treeSet.add(student);
}
System.out.println("名次\t姓名\t语文\t数学\t英语\t总分");
int i=0;
for (Student student : treeSet) { System.out.println((++i)+"\t"+student.getName()+"\t"+student.getChineseScore()+"\t"+student.getMathScore()+"\t"+student.getEnglishScore()+"\t"+student.getTotalScore());
}
}
}
public class Student {
private String name;
private int chineseScore;
private int mathScore;
private int englishScore;
public Student() {
}
public Student(String name, int chineseScore, int mathScore, int englishScore) {
this.name = name;
this.chineseScore = chineseScore;
this.mathScore = mathScore;
this.englishScore = englishScore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChineseScore() {
return chineseScore;
}
public void setChineseScore(int chineseScore) {
this.chineseScore = chineseScore;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getEnglishScore() {
return englishScore;
}
public void setEnglishScore(int englishScore) {
this.englishScore = englishScore;
}
//获取总分的方法
public int getTotalScore(){
return chineseScore+englishScore+mathScore;
}
}
his.chineseScore = chineseScore;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getEnglishScore() {
return englishScore;
}
public void setEnglishScore(int englishScore) {
this.englishScore = englishScore;
}
//获取总分的方法
public int getTotalScore(){
return chineseScore+englishScore+mathScore;
}
}