SYQY网游福利站-新活动速递_热门攻略_礼包中心

Set 是 Collection 接口的子接口,Set 接口没有提供额外的方法。

Set 类型的集合不允许包含相同的元素,若把两个相同的元素加入同一个 Set 类型的集合中,则添加操作会失败。

Set 类型的集合支持的遍历方式和 Collection 类型的集合一样,可以用 foreach 和 iterator。Set 接口的常用实现类有 HashSet、TreeSet。

Java HashSet实现类

HashSet 是 Set 接口的主要实现类,使用 Set 类型的集合时通常会使用这个实现类。

HashSet 用哈希算法存储集合中的元素,因此具有很好的存储、查找、删除等性能。HashSet 不能保证元素的排列顺序,不是线程安全的,集合元素可以是 null。

【实例】创建集合,使用 HashSet 实现集合中基本的功能,代码如下:

import java.util.HashSet;

public class SetDemo {

public static void main(String[] args) {

SetDemo setDemo = new SetDemo();

setDemo.testSet();

}

public void testSet() {

// 创建 HashSet 集合并添加元素

HashSet hashSet = new HashSet();

hashSet.add("a");

hashSet.add("b");

hashSet.add("c");

System.out.println(hashSet);

}

}

在上述代码中,调用 add() 方法实现了元素添加,使用的是 Collection 接口的方法。在 Set 接口中没有可以修改的方法,可以查看 Collection 接口的方法,直接使用即可。

判断集合中两个元素相等的标准:两个对象通过 hashCode() 方法得到的哈希值相等,且两个对象的 equals() 方法返回值为 true。

对存放在 Set 类型的集合中的对象,对应的类一定要重写 hashCode() 和 equals() 方法,以符合对象相等规则,即“相等的对象必须具有相等的哈希值”。

HashSet 类型的集合中元素的无序性不等同于随机性,这里的无序性与元素的添加位置有关。具体来说,我们在添加每个元素到数组中时,具体的存储位置都是由元素的 hashCode() 调用后返回的哈希值决定的,导致在数组中的每个元素不是依次紧密存放的,表现出一定的无序性。

【实例】创建集合和 Student 类,在 HashSet 类型的集合中判断两个对象是否相等,代码如下:

import java.util.Objects;

public class Student {

private Integer id;

private String name;

private Integer age;

public Student(Integer id, String name, Integer age) {

this.id = id;

this.name = name;

this.age = age;

}

public Student() {

}

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = 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 Objects.equals(id, student.id) &&

Objects.equals(name, student.name) &&

Objects.equals(age, student.age);

}

@Override

public int hashCode() {

return Objects.hash(id, name, age);

}

@Override

public String toString() {

return "Student{" +

"id=" + id +

", name='" + name + '\'' +

", age=" + age +

'}';

}

}

import java.util.HashSet;

public class SetDemo {

public static void main(String[] args) {

Student student = new Student(1, "张三", 20);

Student student02 = new Student(1, "张三", 20);

HashSet hashSet = new HashSet();

hashSet.add(student);

hashSet.add(student02);

System.out.println(hashSet);

}

}

程序运行结果为:

[Student{id=1, name='张三', age=20}]

上述代码创建了 Student 类,并在 Student 类中实现了 hashCode() 方法和 equals() 方法。两个对象通过调用 HashSet 类型集合的 hashCode() 和 equals() 方法来确定元素的唯一性,如果两个对象的 hashCode() 返回值相同,并且 equals() 方法返回 true,HashSet 类型集合就会认为这两个对象是相同的元素,因此只保留其中一个,无法重复添加。

Java TreeSet实现类

TreeSet 是 SortedSet 接口的实现类,可根据指定的属性顺序对集合中的元素。进行遍历,TreeSet 底层使用红黑树结构存储数据。

TreeSet 有两种排序方法,分别是自然排序和定制排序。在默认情况下,TreeSet 采用自然排序。

1) 自然排序

TreeSet 首先调用 compareTo() 方法来比较元素的大小,然后将集合元素按升序(默认情况)排列。

【实例】创建集合和 Student 类,按照对象的年龄从小到大进行排序,采用自然排序方法,代码如下:

import java.util.Comparator;

import java.util.Objects;

public class Student implements Comparable {

private Integer id;

private String name;

private Integer age;

public Student(Integer id, String name, Integer age) {

this.id = id;

this.name = name;

this.age = age;

}

public Student() {

}

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = 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 Objects.equals(id, student.id) &&

Objects.equals(name, student.name) &&

Objects.equals(age, student.age);

}

@Override

public int hashCode() {

return Objects.hash(id, name, age);

}

@Override

public String toString() {

return "Student{" +

"id=" + id +

", name='" + name + '\'' +

", age=" + age +

'}';

}

@Override

public int compareTo(Object o) {

if (this == o) {

return 0;

}

if (o instanceof Student) {

Student student = (Student) o;

int value = this.age - student.age;

if (value != 0) {

return value;

}

// 年龄相同时按姓名降序

return -this.name.compareTo(student.name);

}

throw new RuntimeException("输入的类型不匹配");

}

}

import java.util.TreeSet;

public class SetDemo {

public static void main(String[] args) {

Student student = new Student(1, "王五", 20);

Student student02 = new Student(2, "张三", 30);

Student student03 = new Student(3, "小花", 33);

Student student04 = new Student(4, "笑笑", 24);

TreeSet treeSet = new TreeSet<>();

treeSet.add(student);

treeSet.add(student02);

treeSet.add(student03);

treeSet.add(student04);

System.out.println(treeSet);

}

}

程序运行结果为:

[Student{id=1, name='王五', age=20}, Student{id=4, name='笑笑', age=24}, Student{id=2, name='张三', age=30}, Student{id=3, name='小花', age=33}]

在上述代码中,把一个对象添加到 treeSet 集合中时,该对象的类必须实现 Comparable 接口,实现 Comparable 接口的类必须实现 compareTo() 方法,两个对象通过 compareTo() 方法的返回值来比较大小。

2) 定制排序

如果对象所属的类没有实现 Comparable 接口,或不希望按照升序(默认情况)排列,就可以考虑使用定制排序。定制排序通过 Comparator 接口实现,需要重写 compare(Object o1, Object o2) 方法。

【实例】创建集合和 Student 类,按照对象中的年龄从小到大进行排序,采用定制排序方法,代码如下:

import java.util.Objects;

public class Student02 {

private Integer id;

private String name;

private Integer age;

public Student02(Integer id, String name, Integer age) {

this.id = id;

this.name = name;

this.age = age;

}

public Student02() {

}

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

@Override

public boolean equals(Object o) {

if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

Student02 student = (Student02) o;

return Objects.equals(id, student.id) &&

Objects.equals(name, student.name) &&

Objects.equals(age, student.age);

}

@Override

public int hashCode() {

return Objects.hash(id, name, age);

}

@Override

public String toString() {

return "Student{" +

"id=" + id +

", name='" + name + '\'' +

", age=" + age +

'}';

}

}

import java.util.Comparator;

import java.util.TreeSet;

public class SetDemo04 {

public static void main(String[] args) {

Student02 student = new Student02(1, "王五", 20);

Student02 student02 = new Student02(2, "张三", 30);

Student02 student04 = new Student02(4, "笑笑", 24);

Student02 student03 = new Student02(3, "小花", 33);

Comparator comparator = new Comparator() {

@Override

public int compare(Student02 o1, Student02 o2) {

if (o1 instanceof Student02 && o2 instanceof Student02) {

Student02 s1 = (Student02) o1;

Student02 s2 = (Student02) o2;

int value = s1.getAge() - s2.getAge();

if (value != 0) {

return value;

}

return s1.getName().compareTo(s2.getName());

}

throw new RuntimeException("输入的类型不匹配");

}

};

TreeSet treeSet = new TreeSet<>(comparator);

treeSet.add(student);

treeSet.add(student02);

treeSet.add(student03);

treeSet.add(student04);

System.out.println(treeSet);

}

}

程序运行结果为:

[Student{id=1, name='王五', age=20}, Student{id=4, name='笑笑', age=24}, Student{id=2, name='张三', age=30}, Student{id=3, name='小花', age=33}]

在上述代码中,利用 compare(Object o1, Object o2) 方法比较 o1 和 o2 的大小:若返回正整数,则表示 o1 大于 o2;若返回 0,则表示两者相等;若返回负整数,则表示 o1 小于 o2。要实现定制排序,需要将实现 Comparator 接口的实例作为形式参数传递给 TreeSet 的构造器。