JavaSE——集合(四)Collection的子接口set
1、Set结构
1.1、set的性质
set中没有额外定义新的方法,使用的都是Collection中声明过的方法
一、Set:存储的无序性,不可重复的数据
以HashSet为例
1、无序性不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值进行添加
2、不可重复性,保证添加的元素按照equals()判断时,不能返回true。
2、HashSet
二、添加元素的过程
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值通过散列函数计算出在HashSet底层数组中的存放位置(索引位置),判断数组此位置上是否已经有元素:
没有其他元素则直接添加元素a
有元素b或不止一个则比较元素a与元素b的hash值,若hash值不相同,则直接添加a;若hash值相同,调用a的equals方法进行值的比较,若已经存在则不能添加。
若添加成功,在jdk7中,新加入的元素放在数组中指向旧元素,jdk8反过来。
2.1、重写hashCode()方法
- 不重写hashCode()的情况
public class test {
public static void main(String[] args) {
HashSet a = new HashSet();
a.add(1);
a.add(new People("dcd",20));
a.add(new People("dcd",20));
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}
class People{
String name;
int age;
People(){}
People(String n,int a){
name=n;
age=a;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age && Objects.equals(name, people.name);
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
可以发现并没有去除相同的对象,因为对于自定义的类来说,默认生成的是Object.hashCode(),此哈希值具有随机性,就会导致两个内容相同的对象分在了不同的位置上面,就造成了这样的结果,解决这种问题,就需要重写hashCode()方法,注意要和equals()方法一块儿写。
- 重写后的输出
import java.util.*;
public class test {
public static void main(String[] args) {
HashSet a = new HashSet();
a.add(1);
a.add(new People("dcd",20));
a.add(new People("dcd",20));
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}
class People{
String name;
int age;
People(){}
People(String n,int a){
name=n;
age=a;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age && Objects.equals(name, people.name);
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
- hashCode()重写的源代码
3、LinkedHashSet
无序体现在存放的时候依然是按照hash值去存放的,LinkedHashSet能够按照添加的顺序输出的原因是使用双向链表实现的。
对于频繁的遍历操作,效率比HashSet要高。
4、TreeSet
向TreeSet中添加的数据,要求是相同类的对象,不能添加不同类的对象,底层是一个红黑树
- 正常数据可以自动排序
public class test {
public static void main(String[] args) {
TreeSet a = new TreeSet();
a.add(1);
a.add(8);
a.add(-1);
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}//-1 1 8
- 自定义类如果不进行comparable的重写是无法进行排序的。TreeSet不会调用equals函数的,他会调用Comparable进行比较,需要注意。
自然排序
import java.util.*;
public class test {
public static void main(String[] args) {
TreeSet a = new TreeSet();
a.add(new People("Tom",20));
a.add(new People("Tom",18));
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}
class People implements Comparable{
String name;
int age;
People(){}
People(String n,int a){
name=n;
age=a;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
People people = (People) o;
return age == people.age && Objects.equals(name, people.name);
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public int compareTo(Object o) {
if(o instanceof People){
People p=(People) o;
if(this.name.compareTo(p.name)!=0) return this.name.compareTo(p.name);
else return Integer.compare(this.age,p.age);
}else throw new RuntimeException("输入错误");
}
}
定制排序
public class test {
public static void main(String[] args) {
Comparator com=new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof People&&o2 instanceof People){
People a=(People) o1;
People b=(People) o2;
if(a.name.compareTo(b.name)!=0) return a.name.compareTo(b.name);
else return Integer.compare(a.age,b.age);
}else throw new RuntimeException("输入错误");
}
};
TreeSet a = new TreeSet();
a.add(new People("Tom",20));
a.add(new People("Tom",18));
Iterator it = a.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
}
}
}