Set集合(接口)
1.概述:Set集合继承自Collection接口集合
2.Set集合特点:
(1)Set集合中储存的元素无序(存取不一致)
(2)Set集合中储存的元素唯一,不重复(Set接口底层数据是一个哈希表)
3.Set集合为接口,所以要靠子实现类HashSet,TreeSet来实现
注:Set集合和List集合的区别
(1)List集合元素可以重复,并且存在有序性(存储和取出一致)
(2)Set集合元素唯一不可重复,并且存在无序性(存储和取出不一致)
例:
import java.util.Set;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("hello");
set.add("hello");
set.add("java");
set.add("world");
set.add("world");
for(String str:set) {
System.out.println(str);
}
}
}
HashSet集合(Set的子实现类)
public class HashCodeDemo {
public static void main(String[] args) {
System.out.println("hello".hashCode());
System.out.println("hello".hashCode());
System.out.println("world".hashCode());
System.out.println("world".hashCode());
/**
结果:
99162322
99162322
113318802
113318802
*/
}
}
import java.util.HashSet;
//测试类
public class HashSetDemo {
public static void main(String[] args) {
//创建一个HashSet集合对象
HashSet<Student> hs = new HashSet<Student>() ;
//创建学生对象
Student s1 = new Student("高圆圆", 27) ;
Student s2 = new Student("张三", 25) ;
Student s3 = new Student("唐嫣", 26) ;
Student s4 = new Student("邓超", 29) ;
Student s5 = new Student("胡歌", 23) ;
Student s6 = new Student("高圆圆", 27) ;
//给集合中添加学生对象
hs.add(s1) ;
hs.add(s2) ;
hs.add(s3) ;
hs.add(s4) ;
hs.add(s5) ;
hs.add(s6) ;
//增强for遍历
for(Student s : hs){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
//学生类
class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(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;
}
//给集合中添加自定义对象则需重写此类中的hashcode和equals()方法!
@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;
Student other = (Student) 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;
}
}
LinkedHashSet集合(HashSet类的子类)
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args) {
//创建LinkedHashSet集合对象
LinkedHashSet<String> link = new LinkedHashSet<String>();
//给集合中添加元素
link.add("hello") ;
link.add("world") ;
link.add("world") ;
link.add("Java") ;
link.add("Java") ;
link.add("JavaWeb") ;
link.add("JavaWeb") ;
//遍历集合
for(String str: link){
System.out.println(str);
}
}
}
TreeSet集合(Set接口的子实现类)
1.概述:TreeSet集合底层是依赖于TreeMap的实例,而TreeMap依赖于红黑树结构实现
红黑树结构图解:
2.TreeSet集合两种排序方式(两中排序的不同取决于不同的构造方法):
(1)自然排序(无参构造:public TreeSet()根据其元素的自然顺序进行排序)
自定义对象则需实现Comparable<T>接口,重写public int compareTo()方法
注:Comparable接口后需接泛型
(2)比较器排序(构造方法:public TreeSet(Comparator<E> comparator)比较器排序)
自定义对象需重写Comparator接口中的public int compare(T o1 , T o2) 方法
注:一般采用匿名内部类的方式
Comparator接口后需加泛型
3.自然排序:
(1)例:集合存储Integer和String类型则比较元素第一位的自然顺序
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args){
//创建TreeSet集合对象
//构造方法:public TreeSet() 无参构造:根据其元素的自然顺序进行排序
TreeSet<Integer> ts = new TreeSet<Integer>();
//添加元素
ts.add(20) ;
ts.add(18) ;
ts.add(23) ;
ts.add(22) ;
ts.add(17) ;
ts.add(24) ;
ts.add(19) ;
ts.add(18) ;
ts.add(24) ;
//遍历集合
for(Integer i : ts){
System.out.print(i+ " ");
}
}
}
(2)TreeSet集合储存自定义对象并遍历:
此遍历方式实现了Comparable<T>接口,重写了compareTo(T o)方法
元素唯一取决于compareTo方法返回值是否为0(为0则相同)!!
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象
TreeSet<Student> ts = new TreeSet<Student>() ;
//创建学生对象
Student s1 = new Student("linqingxia", 28) ;
Student s2 = new Student("fengqingy", 28) ;
Student s3 = new Student("gaoyuanyuan", 27) ;
Student s4 = new Student("liushishi", 26) ;
Student s5 = new Student("wanglihong", 29) ;
Student s6 = new Student("zhangguorong", 30) ;
Student s7 = new Student("zhangguorong", 30) ;
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
//遍历
for(Student s : ts){
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
//对于TreeSet集合存储自定义对象必须实现一个接口:compareable接口
class Student implements Comparable<Student>{
private String name ;
private int age ;
public Student() {
super();
}
public Student(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;
}
//重写compareTo()方法
public int compareTo(Student s) {
//排序的代码了,需要定义排序的条件
//主要条件:按照学生的年龄从小到大进行排序
int num =this.age - s.age ;//年龄从小到到
//当num==0认为年龄一样,年龄一样,不代表姓名的的内容是否相同,需要自己给出次要条件
int num2 = num==0 ? this.name.compareTo(s.name): num ;
return num2 ;
}
}
4.比较器排序
依赖于构造方法:public TreeSet(Comparator<E> comparator)
注:Comparator作为参数进行传递,则需要该接口的自实现类来进行实现
(1)方式一:自定义一个类来实现Comparator接口,作为子实现类
/*
* 需求:按照学生姓名从小到大进行排序
*
* 元素唯一性:取决于返回值是否为0
* */
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建TreeSet集合使用比较器进行给元素进行排序
//public TreeSet(Comparator<E> comparator):有参构造
TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()) ;
//创建学生对象
Student s1 = new Student("gaoyuanyan", 27) ;
Student s2 = new Student("liushishi", 22);
Student s3 = new Student("fengqingy", 23) ;
Student s4 = new Student("wuqilong", 35) ;
Student s5 = new Student("gaoyuanyuan",27) ;
Student s6 = new Student("zhangguorong",29) ;
Student s7 = new Student("gaoyuanyuan",26) ;
//添加元素
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
//增强for遍历
for(Student s : ts){
System.out.println(s.getName()+"----"+s.getAge());
}
}
}
//MyComparatpr是Comparator接口的子实现类
class MyComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
//比较姓名长度是否一样
int num = s1.getName().length() - s2.getName().length() ;
//次要条件:姓名长度一样,还要比较姓名的内容是否一样
int num2 = num==0 ? s1.getName().compareTo(s2.getName()): num ;
//姓名长度和内容都一样,还需比较两个人的年龄是否一样
int num3 = num2 ==0 ? s1.getAge() - s2.getAge() : num2 ;
return num3 ;
}
}
//自定义类
class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(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;
}
}
(2)方式二:使用接口的匿名内部类来实现
匿名内部类格式:new 接口名或者类名(){
重写方法() ;
}
/*
* 需求:按照学生姓名从小到大进行排序
*
* 元素唯一性:取决于返回值是否为0
* */
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建TreeSet集合使用比较器进行给元素进行排序
//public TreeSet(Comparator<E> comparator):有参构造
/**
* 格式
* new 接口名或者类名(){
* 重写方法() ;
* }
*/
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//比较姓名长度是否一样
int num = s1.getName().length() - s2.getName().length() ;
//次要条件:姓名长度一样,还要比较姓名的内容是否一样
int num2 = num==0 ? s1.getName().compareTo(s2.getName()): num ;
//姓名长度和内容都一样,还需比较两个人的年龄是否一样
int num3 = num2 ==0 ? s1.getAge() - s2.getAge() : num2 ;
return num3 ;
}
}) ;
//创建学生对象
Student s1 = new Student("gaoyuanyan", 27) ;
Student s2 = new Student("liushishi", 22);
Student s3 = new Student("fengqingy", 23) ;
Student s4 = new Student("wuqilong", 35) ;
Student s5 = new Student("gaoyuanyuan",27) ;
Student s6 = new Student("zhangguorong",29) ;
Student s7 = new Student("gaoyuanyuan",26) ;
//添加元素
ts.add(s1) ;
ts.add(s2) ;
ts.add(s3) ;
ts.add(s4) ;
ts.add(s5) ;
ts.add(s6) ;
ts.add(s7) ;
//增强for遍历
for(Student s : ts){
System.out.println(s.getName()+"----"+s.getAge());
}
}
}
//自定义类
class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(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;
}
}
课堂练习
/*
* 需求:键盘录入五个学生的信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低进行输出
*
* 分析:
* (1)创建一个学生类,提供姓名以及各科成绩等成员变量
* (2)创建TreeSet集合对象:TreeSet<Student>(Comparator<Student> com)
* (3)条件分析:
* 主要:总分从高到低
* 次要:若总分相同,比较各科成绩是否相同
* (4)键盘录入五个学生对象(for循环)
* (5)输出
* */
import java.util.Scanner;
import java.util.TreeSet;
import java.util.Comparator;
//测试类
public class TreeSetTest {
public static void main(String[] args) {
// 创建TreeSet集合对象
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
public int compare(Student s1, Student s2) {
// 比较总分
int num1 = s2.getSum() - s1.getSum();
// 总分相同,比较语文成绩
int num2 = num1 == 0 ? s2.getChinese() - s1.getChinese() : num1;
// 语文相同,则比较数学成绩
int num3 = num2 == 0 ? s2.getMath() - s1.getMath() : num2;
// 若以上条件都相同则比较名字内容是否相同
int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()) : num3;
return num4;
}
});
System.out.println("请录入学生信息:");
for (int i = 1; i <= 5; i++) {
Scanner sc = new Scanner(System.in);
// 录入学生信息
System.out.println("请输入第" + i + "学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入第" + i + "个学生的语文成绩:");
String chineseScore = sc.nextLine();
System.out.println("请输入第" + i + "个学生的数学成绩:");
String mathScore = sc.nextLine();
System.out.println("请输入第" + i + "个学生的英语成绩:");
String englishScore = sc.nextLine();
// 创建学生对象,将以上信息封装到学生对象中
Student s = new Student(name, Integer.parseInt(chineseScore), Integer.parseInt(mathScore),
Integer.parseInt(englishScore));
// s.setName(name);
// s.setChinese(Integer.parseInt(chineseScore));
// s.setMath(Integer.parseInt(mathScore));
// s.setEnglish(Integer.parseInt(englishScore));
// 将学生对象添加至集合中
ts.add(s);
}
System.out.println("学生信息总分从高到底排列顺序如下:");
// 使用增强for循环遍历
for (Student s : ts) {
System.out.println(s);
}
}
}
// 学生类
class Student {
private String name;
private int chinese;
private int math;
private int english;
Student() {
}
Student(String name, int chinese, int math, int english) {
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getChinese() {
return chinese;
}
public void setMath(int math) {
this.math = math;
}
public int getMath() {
return math;
}
public void setEnglish(int english) {
this.english = english;
}
public int getEnglish() {
return english;
}
// 获取总分的方法
public int getSum() {
return chinese + math + english;
}
public String toString() {
return "[" + name + ":" + chinese + "," + math + "," + english + "]";
}
}
/*
* 测试:
*
* 请录入学生信息:
* 请输入第1学生的姓名: 伊卡尔迪
* 请输入第1个学生的语文成绩: 78
* 请输入第1个学生的数学成绩: 87
* 请输入第1个学生的英语成绩: 90
* 请输入第2学生的姓名: 佩里西奇
* 请输入第2个学生的语文成绩: 67
* 请输入第2个学生的数学成绩: 98
* 请输入第2个学生的英语成绩: 90
* 请输入第3学生的姓名: 坎德雷瓦
* 请输入第3个学生的语文成绩: 99
* 请输入第3个学生的数学成绩: 89
* 请输入第3个学生的英语成绩: 91
* 请输入第4学生的姓名: 汉达诺维奇
* 请输入第4个学生的语文成绩: 90
* 请输入第4个学生的数学成绩: 90
* 请输入第4个学生的英语成绩: 89
* 请输入第5学生的姓名: 加利亚迪尼
* 请输入第5个学生的语文成绩: 88
* 请输入第5个学生的数学成绩: 96
* 请输入第5个学生的英语成绩: 98
* 学生信息总分从高到底排列顺序如下:
* [加利亚迪尼:88,96,98]
* [坎德雷瓦:99,89,91]
* [汉达诺维奇:90,90,89]
* [伊卡尔迪:78,87,90]
* [佩里西奇:67,98,90]
*
*/