JAVA容器-Set接口容器详解
JAVA容器系列专题
【JAVA容器概论】
【JAVA容器-List接口容器详解】
【JAVA容器-迭代器Iterator详解】
【JAVA容器-Set接口容器详解】
【JAVA容器-Map接口容器详解】
【JAVA容器演进及应用(含对Disruptor的浅解)】
Set接口容器关系图
HashSet的使用
底层实现:哈希表(数组+链表)
public class TestHashSet {
//这是main方法,程序的入口
public static void main(String[] args) {
//创建一个HashSet集合:保存Integer类型元素
HashSet<Integer> hs = new HashSet<>();
System.out.println(hs.add(19));//返回true
hs.add(5);
hs.add(20);
//返回false,因为集合中已经有19,所以这个19没有放入到集合中
System.out.println(hs.add(19));
hs.add(41);
hs.add(0);
// 元素无序且唯一
System.out.println(hs.size());
System.out.println(hs);
//创建一个HashSet集合:保存String类型元素
HashSet<String> hs1 = new HashSet<>();
hs1.add("hello");
hs1.add("apple");
hs1.add("banana");
hs1.add("html");
hs1.add("apple");
hs1.add("css");
// 元素无序且唯一
System.out.println(hs1.size());
System.out.println(hs1);
//创建一个HashSet集合:保存Student对象元素
HashSet<Student> hs2 = new HashSet<>();
hs2.add(new Student(19,"lili"));
hs2.add(new Student(20,"lulu"));
hs2.add(new Student(18,"feifei"));
hs2.add(new Student(19,"lili"));
hs2.add(new Student(10,"nana"));
// 元素无序,但是唯一
System.out.println(hs2.size());
System.out.println(hs2);
}
}
代码执行结果反思
执行结果发现:
- 对于存储顺序来说,HashSet存储无序。
- HashSet中存储Integer、String都能实现元素无序且唯一,但是存储自定义对象却不能实现元素唯一。
- Integer、String类型存储多次时,只有第一次存储成功,其余都存储失败。
LinkedHashSet的使用
底层实现:哈希表+链表
public class TestSet {
public static void main(String[] args) {
System.out.println("--------------testLinkedHashSet-------------");
testLinkedHashSet();
System.out.println("--------------testHashSet-------------");
testHashSet();
}
private static void testLinkedHashSet() {
LinkedHashSet<Integer> hs = new LinkedHashSet<>();
System.out.println(hs.add(19));//true
hs.add(25);
hs.add(20);
System.out.println(hs.add(19));//false 这个19没有放入到集合中
hs.add(41);
hs.add(0);
System.out.println(hs.size());//唯一,无序
System.out.println(hs);
}
private static void testHashSet() {
HashSet<Integer> hs = new HashSet<>();
System.out.println(hs.add(19));//true
hs.add(25);
hs.add(20);
System.out.println(hs.add(19));//false 这个19没有放入到集合中
hs.add(41);
hs.add(0);
System.out.println(hs.size());//唯一,无序
System.out.println(hs);
}
}
代码执行结果
代码执行结果反思
- 对于存储顺序来说,LinkedHashSet存储有序,HashSet存储无序。
- LinkedHashSet与HashSet相同,存储的元素都是唯一的。
TreeSet的使用
底层实现:二叉树
测试代码
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class TestSet {
public static void main(String[] args) {
System.out.println("--------------testTreeSet-------------");
testTreeSet();
}
private static void testTreeSet() {
TreeSet<Student> s = new TreeSet<>();
s.add(new Student(14,"wk"));
s.add(new Student(2,"tk"));
s.add(new Student(10,"sjc"));
System.out.println(s.add(new Student(20, "wj")));
s.add(new Student(33,"xyc"));
System.out.println(s.add(new Student(20, "wj")));
s.add(new Student(5,"tzl"));
System.out.println(s.size());
System.out.println(s);
}
}
执行结果
反思
因为没有在TreeSet存储的自定义对象中重写排序方法,所以抛异常了,所以TreeSet中存储的元素一定要实现排序方法。
代码修改
public class Student implements Comparable<Student>{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
return this.getAge() - o.getAge();
}
}
执行结果
反思
自定义对象实现Comparable接口,并重写compareTo(),执行成功。
比较器实现
原理
比较器实现的原理就是根据业务逻辑返回【=0,<0,>0】三种值,然后根据返回值放入TreeSet的底层二叉树。
内部比较器
Demo
TreeSet中的Student类属于【内部比较器】。
简介
自定义对象实现Comparable接口,并重写compareTo()。
外部比较器
方式一:新建比较器类
Demo
public class MyCompare implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
简介
新建一个类,实现Comparator接口,并重写compare()。
方式二:比较器简略写法
Demo
public class TestSet {
public static void main(String[] args) {
System.out.println("--------------testTreeSet-------------");
testTreeSet();
}
private static void testTreeSet() {
TreeSet<Student> s = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
s.add(new Student(14,"wk"));
s.add(new Student(2,"tk"));
s.add(new Student(10,"sjc"));
System.out.println(s.add(new Student(20, "wj")));
s.add(new Student(33,"xyc"));
System.out.println(s.add(new Student(20, "wj")));
s.add(new Student(5,"tzl"));
System.out.println(s.size());
System.out.println(s);
}
}
简介
在实例化TreeSet时直接new一个Comparator接口并重写compare()。
反思
- 内部比较器只能实现一种比较方式,不推荐。
- 外部比较器可以按需为一个自定义对象创建多种比较方式,并且写法简单,推荐使用。