Set集合框架的概述及应用
我们可以通过查询API文档来来了解Set集合框架
Set集合框架就是一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。
这样我们可以了解到Set集合框架其实就是一个里面不能存放相同元素的集合.
HashSet集合的概述及应用
我们可以通过查询API文档来来了解HashSet集合框架
此类实现 Set
接口,由哈希表(实际上是一个 HashMap
实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null
元素。 此类为基本操作提供了稳定性能,这些基本操作包括 add
、remove
、contains
和 size
,假定哈希函数将这些元素正确地分布在桶中。对此 set 进行迭代所需的时间与 HashSet
实例的大小(元素的数量)和底层 HashMap
实例(桶的数量)的“容量”的和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
我们需要知道HashSet的底层数据结构是哈希表,里面的集合元素可以是Null,哈希表是一个元素为链表的数组(哈希表)其综合了数组和链表的优点。
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,
然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
HashSet 集合判断两个元素相等的标准:
两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
结论:HashSet 保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证。这里我们需要注意一点,String类和Integer类里JAva是已将类中的hashcode方法和equals方法重写过的,所以当我们直接存储String对象和Integet对象的时候,我们可以直接将元素存入,元素的存入后直接就能保证集合内元素的唯一。
这里我们来创建一个Hash Set集合来存入一个自定义的Student对象并对其进行遍历
import java.util.Objects;
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 void show () {
System.out.println(name +"..."+age);
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
@Override
public boolean equals(Object 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 Objects.hash(name, age);
}
// int num=this.name.length()-obj.name.length();
// //如果姓名长度一样再比较年龄
// int num2=(num==0)?this.age-obj.age:num;
// //如果年龄相同 再比较姓名
// int num3=(num2==0)?this.name.compareTo(obj.name):num2;
@Override
public int compareTo(Student o) {
int num=this.getName().compareTo(o.getName());
int num2=(num==0)?this.getAge()-o.getAge():num;
return num2;
}
}
``
public class ha {
public static void main(String[] args) {
Student s1=new Student("小花",12);
Student s2=new Student("小花",13);
Student s3=new Student("小花花",12);
Student s4=new Student("小花花花花",12);
Student s5=new Student("小花花花",12);
Student s6=new Student("小花花花",12);
HashSet<Student> studay=new HashSet<>();
studay.add(s1);
studay.add(s2);
studay.add(s3);
studay.add(s4);
studay.add(s5);
studay.add(s6);
for (Student student : studay) {
System.out.println(student.getName()+student.getAge());
}
}
}
输出结果:
可见存取的集合元素唯一且无序,当然这个对象的类里我们是将hashcode方法和equals方法重写过的,如果没有重写。这个集合元素的元素是不会唯一的,也就是说里面的S5和S6都会存在这个集合之中。
LinkedHashSet的概述及特点
同样我们通过ApI文档来查询这个类的说明来进行了解
LinkedHashSet集合框架具有可预知迭代顺序的 Set
接口的哈希表和链接列表实现。此实现与 HashSet
的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。(如果在 s.contains(e)
返回 true
后立即调用 s.add(e)
,则元素 e
会被重新插入到 set s
中。)
可以从内容了解到LinkedHashSet这个集合框架它在存储的时候,是采取的有序存储,同时他也是集合内的元素唯一的,不允许重复,同HashSet集合一样,它也是通过hashcode方法和equals方法来进行集合内元素唯一性的保证的,所以我们如果要给LinkedHashSet中存储自定义对象元素的时候,我们必须将对象类中的Hash code方法和equals方法进行重写。
同样我们对上建立的Student类创建对象存入LinkedHashSet集合之中:
import java.util.HashSet;
import java.util.LinkedHashSet;
public class ha {
public static void main(String[] args) {
Student s1=new Student("小花",12);
Student s2=new Student("小花",13);
Student s3=new Student("小花花",12);
Student s4=new Student("小花花花花",12);
Student s5=new Student("小花花花",12);
Student s6=new Student("小花花花",12);
LinkedHashSet<Student> studay=new LinkedHashSet<>();
studay.add(s1);
studay.add(s2);
studay.add(s3);
studay.add(s4);
studay.add(s5);
studay.add(s6);
for (Student student : studay) {
System.out.println(student.getName()+student.getAge());
}
}
}
输出结果:
可见这个集合里我们是如何存入的元素,遍历该集合就会按照存入的顺序进行取出。
TreeSet集合的特点及应用
这里同样我们在APi里对TreeSet集合的说明进行查询
**基于 TreeMap
的 NavigableSet
实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator
进行排序,具体取决于使用的构造方法。 **
这个说明的内容看起来不是特别的明了,我来给简单的解释一下,这个TreeSet集合它和其他的两个集合的功能是一致的,它可以存储一些引用数据类型的集合,而且存储的元素同样唯一,和其他两个(HashSet 、LinkedHashSet)的不同点是,它可以将存储的元素,存储的时候是用的方式进行在遍历的时候按照元素的一定 顺序取出,而这个取出顺序的确定我们可以通过两种方法进行:第一种是需要我们对该类实现的Comparator接口下的Compare To方法进行重写,由方法的重写后取到的返回值进行判断。第二种是构造一个Comparator比较器,根据比较器的返回值来进行判断取出顺序。
我们同样可以对以上的自定义Student对象进行存储和排序。
import java.util.TreeSet;
public class ha {
public static void main(String[] args) {
Student s1=new Student("小花",12);
Student s2=new Student("小花",13);
Student s3=new Student("小花花",12);
Student s4=new Student("小花花花花",12);
Student s5=new Student("小花花花",12);
Student s6=new Student("小花花花",12);
TreeSet<Student> studay=new TreeSet<>();
studay.add(s1);
studay.add(s2);
studay.add(s3);
studay.add(s4);
studay.add(s5);
studay.add(s6);
for (Student student : studay) {
System.out.println(student.getName()+student.getAge());
}
}
}
输出结果:
从结果我们可以看到从集合里取出是先按照对象的名字进行从小到大的进行判断,如果对象的名字相同的话 ,就根据对象的年龄进行判断。当然这个与我们重写的Comparato方法是由关的,我们就是通过这个Comparato方法进行规定排序的规则。当然我们还有另一种方法,那就是我们通过比较器内方法的重写,来确定排序的规则。
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;
public class ha {
public static void main(String[] args) {
Student s1=new Student("小花",12);
Student s2=new Student("小花",13);
Student s3=new Student("小花花",12);
Student s4=new Student("小花花花花",12);
Student s5=new Student("小花花花",12);
Student s6=new Student("小花花花",12);
TreeSet<Student> studay=new TreeSet<>(new Comparator<Student>() {
@Override
//int num=this.name.length()-obj.name.length();
// //如果姓名长度一样再比较年龄
// int num2=(num==0)?this.age-obj.age:num;
// //如果年龄相同 再比较姓名
// int num3=(num2==0)?this.name.compareTo(obj.name):num2;
public int compare(Student o1, Student o2) {
int num=o1.getAge()-o2.getAge();
int num2=(num==0)?o1.getName().length()-o2.getName().length():num;
int num3=(num2==0)?o1.getName().compareTo(o2.getName()):num2;
return num3;
}
});
studay.add(s1);
studay.add(s2);
studay.add(s3);
studay.add(s4);
studay.add(s5);
studay.add(s6);
for (Student student : studay) {
System.out.println(student.getName()+student.getAge());
}
}
}
输出结果:
可以观察到,在这个比较器里我们是先 比较了对象的年龄值,如果年龄相同,我们就把名字按字典排序,如果字典排序相同,我们再对其姓名长度进行排序,很明显结果是符合这个规则的,是我们的TreeSet集合的特点。
最后我们来补充总结一下:
HashSet类
Java.util.HashSet类实现了Java.util.Set接口。
它不允许出现重复元素;
不保证和政集合中元素的顺序
允许包含值为null的元素,但最多只能有一个null元素。
TreeSet类:
TreeSet描述的是Set的一种变体——可以实现排序等功能的集合,它在讲对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,并保证该集合元素按照“升序”排列。
HashSet : 为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。
TreeSet : 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。
LinkedHashSet : 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。