Collection<E>
Set<E>
- 不能有重复元素
- 允许null值,且只能存储一个
- Set接口中定义的方法与Collection接口中定义的方法一样
HashSet<E>
- 是Set接口的一个实现类,不允许重复元素,不保证迭代顺序
- 底层是HashMap,在创建HashSet是,同时创建了HashMap,且向HashSet中存储数据时,其实是存储在HashMap的键上
- 允许存储null值
- 不同步,即不保证线程安全
面试题:HashMap扩容机制
去重原理:
在向HashSet中存储元素时(执行add()时),会调用hashCode()和equals()方法
1 在向HashSet中存储元素时,首先将当前元素hashCode值与内存中已有的hashCode值比较有无与相同的
2 如果没有相同的hashCode值,认为内存中无该元素,允许存入
3 如果有相同的hashCode值,那么此时就会调用当前元素的equals()用于和之前元素的内容比较。如果内容相同,就不允许存入;如果内容不同,就允许存入
演示:
public void test2() {
HashSet<Student> stus = new HashSet<>();
Student s1 = new Student(123,"AAA");
Student s2 = new Student(123,"AAA");
Student s3 = new Student(124,"BBB");
Student s4 = new Student(125,"CCC");
Student s5 = new Student(124,"BBB");
Student s6 = new Student(125,"CCC");
System.out.println(stus.add(s1));
System.out.println(stus.add(s2));
System.out.println(stus.add(s3));
System.out.println(stus.add(s4));
System.out.println(stus.add(s5));
System.out.println(stus.add(s6));
System.out.println(stus);
}
public void test1() {
HashSet<String> set = new HashSet<>();
set.add("世");
set.add("界");
set.add("和");
set.add("平");
set.add("!");
System.out.println(set.add("!"));
for (String s : set) {
System.out.println(s);
}
set.remove("!");
System.out.println(set);
}
LinkedHashSet<E>
- 是哈希表和链表实现,即有Set集合不重复的特点,也有链表结构元素有序的特点
- 不重复,能保证迭代顺序
- 方法和HashSet方法一样
演示:
public void test() {
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("AB");
lhs.add("CD");
lhs.add("BC");
lhs.add("CD");
lhs.add("DF");
lhs.add("BC");
System.out.println(lhs);
}
TreeSet<E>
- 底层是TreeMap
- 会将存入的元素进行自然排序 ——》 有序
- (自然顺序是指实现了Comparable接口任意一个类,都可以做的自然顺序)
- 不能存储重复元素
- 不保证线程安全
TreeSet的去重和排序与之前的hashCode()和equals()没有关系
0 向TreeSet中存储的元素,必须是可比较的
可比较方式1:元素要实现Comparable接口
可比较方式2:元素要要参与地Comparator比较器接口中
1 当调用add()方法存储参数时,底层会调用参数本身的comparTo()方法(或者compare()方法)将参数与存在参数比较
2 如果是第一个元素,那就存储 ——》 该元素是根节点
3 如果不是第一个元素,那么该元素将从根节点比较,如果比节点大,存入右树杈,如果比节点小,放入左树杈,相等不存储
演示:
public void test() {
TreeSet<String> ts = new TreeSet<>();
ts.add("a");
ts.add("d");
ts.add("a");
ts.add("c");
ts.add("b");
ts.add("d");
System.out.println(ts);
System.out.println(ts.ceiling("c"));
System.out.println(ts.higher("c"));
System.out.println(ts.first());
System.out.println(ts.last());
ts.pollLast();
System.out.println(ts);
}
public void test1() {
TreeSet<Student> stus = new TreeSet<>();
stus.add(new Student(103,"孙三"));
stus.add(new Student(104,"李四"));
stus.add(new Student(102,"钱二"));
stus.add(new Student(101,"赵大"));
stus.add(new Student(102,"钱二"));
stus.add(new Student(101,"赵大"));
System.out.println(stus);
}
//Student类
public class Student implements Comparable{
private int no;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Student() {
}
public Student(int no, String name) {
this.no = no;
this.name = name;
}
public Student(String name, int no) {
this.no = no;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
if (no != student.no)
return false;
return name.equals(student.name);
}
@Override
public int hashCode() {
int result = no;
result = 31 * result + name.hashCode();
return result;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Object o) {
Student s = (Student)o;
byte[] bytes1 = (this.name).getBytes();
byte[] bytes2 = (s.getName()).getBytes();
int a = bytes1[1] - bytes2[1];
int b = this.no - s.getNo();
return a;
}
}