Set接口的特点、方法、实现类的用法、注意事项、代码练习
12.4 Set集合
12.4.1 Set子接口
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
12.1.2 Set实现类
- HashSet【重点】:
基于HashCode实现元素不重复;
先判断hashCode是否一致,当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入;
HashSet的底层使用的HashMap类,即是将所有需要存入HashSet的值,直接保存在HashMap中;
foreach循环:
for(数据类型 变量名 : 容器名称){//可遍历集合或数组(常用在无序集合)
//逻辑代码
}
import java.util.HashSet;
public class TestHashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<String>();
set.add("A");
set.add("B");
set.add("C");
set.add("D");
System.out.println(set.size());
set.remove("C");
System.out.println(set.size());
System.out.println(set);
//如何获取Set中的元素?
//遍历方式发生改变:foreach循环
for( String s : set ) {
System.out.print(s +"\t");
}
}
}
输出结果:
4
3
[A, B, D]
A B D
import java.util.HashSet;
import java.util.Set;
public class TestHashSet2 {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<Integer>();
System.out.println(numbers.add(11));
numbers.add(22);
numbers.add(33);
numbers.add(44);
numbers.add(55);
numbers.add(66);
numbers.add(77);
numbers.add(88);
numbers.add(99);
System.out.println(numbers.add(11));//重复的无法插入
for (Integer i : numbers) {
System.out.print(i + "\t");
}
System.out.println();
}
}
输出结果:
true
false
33 66 99 22 55 88 11 44 77
import java.util.HashSet;
import java.util.Set;
public class TestHashSet3 {
public static void main(String[] args) {
Student s1 = new Student("Tom" , 18 , "male" , 99D);
Student s2 = new Student("Jack" , 20 , "male" , 97D);
Student s3 = new Student("Michael" , 21 , "male" , 98D);
Student s4 = new Student("Rose" , 19 , "female" , 100D);
Student s5 = new Student("Tom" , 18 , "male" , 99D);//与s1内容相同,但地址不同,可以插入,需要去掉重复
//通过覆盖equals方法实现
Set<Student> students = new HashSet<Student>();
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s1);//去掉了重复 equals--->Object提供的equals方法,内部使用this==obj进行判断
students.add(s5);
//注意:HashSet没有必要在每次插入新值是=时,都去与已有数据进行一一比较
//注意:HashSet使用equals方法进行比较,是有前提的(两个对象的哈希码相同)
for (Student student : students) {
System.out.println(student.toString());
}
}
}
class Student{
String name;
Integer age;
String sex;
Double score;
public Student() {}
public Student(String name, Integer age, String sex, Double score) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
}
//hashCode才是调用equals方法的前提
//只有当两个对象的哈希码相同时,才有必要调用equals方法
@Override
public int hashCode() {
int result = 0 ;
result = this.name.hashCode() + this.age.hashCode() + this.sex.hashCode() + this.score.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {//重写equals方法,以完成比较
System.out.println("Studnet's equals()");//显示equals方法的调用情况
if(this == obj) {
return true;
}
if(obj == null) {
return false;
}
if(this.getClass() != obj.getClass()) {
return false;
}
Student s = (Student)obj;
if( this.name.equals(s.name) && this.age.equals(s.age) && this.sex.equals(s.sex) && this.score.equals(s.score)) {
return true;
}
return false;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score + "]";
}
}
输出结果:
Studnet's equals()
Student [name=Michael, age=21, sex=male, score=98.0]
Student [name=Tom, age=18, sex=male, score=99.0]
Student [name=Jack, age=20, sex=male, score=97.0]
Student [name=Rose, age=19, sex=female, score=100.0]
- LinkedHashSet:
链表实现的HashSet,按照链表进行存储,即可保留演示的插入顺序;
底层使用LinkedHashMap(链表结构)存储,节点的形式完成单独存储数据,并指向下一个节点,通过顺序访问节点,可保留元素的插入顺序;
import java.util.LinkedHashSet;
public class TestLinkedHashSet {
public static void main(String[] args) {
LinkedHashSet<Integer> numbers = new LinkedHashSet<Integer>();
//底层使用LinkedHashMap(链表结构)存储,节点的形式完成单独数据的保存,并指向下一个节点,
//通过顺序访问节点,可保留元素的插入顺序
System.out.println(numbers.add(11));
numbers.add(22);
numbers.add(33);
numbers.add(44);
numbers.add(55);
numbers.add(66);
numbers.add(77);
numbers.add(88);
numbers.add(99);
System.out.println(numbers.add(11));//重复的将无法插入
for (Integer i : numbers) {
System.out.print(i + "\t");
}
System.out.println();
}
}
输出结果:
true
false
11 22 33 44 55 66 77 88 99
- TreeSet:
基于排列顺序实现元素不重复;
实现了SortedSet接口,对集合元素自动排序;
元素对象的类型必须实现Comparable接口,指定排序规则;
通过CompareTo方法确定是否为重复元素,方法返回0做为去重的依据;
import java.util.TreeSet;
public class TestTreeSet {
public static void main(String[] args) {
TreeSet<Integer> nums = new TreeSet<Integer>();
nums.add(1);
nums.add(4);
nums.add(6);
nums.add(5);
nums.add(3);
System.out.println(nums.add(3));//保证元素不重复(唯一)
//CompareTo方法返回0,表示重复
for (Integer integer : nums) {
System.out.print(integer +"\t");
}
System.out.println();
nums.add(2);
for (Integer integer : nums) {
System.out.print(integer +"\t");
}
System.out.println();
}
}
输出结果:
false
1 3 4 5 6
1 2 3 4 5 6
import java.util.TreeSet;
public class TestTreeSet2 {
public static void main(String[] args) {
TreeSet<Student2> students = new TreeSet<Student2>();
students.add( new Student2("Tom" , 20 , "male" , 99D) );
students.add( new Student2("Jack" , 23 , "male" , 92D) );
students.add( new Student2("Anine" , 21 , "female" , 100D) );
students.add( new Student2("Rose" , 19 , "female" , 95D) );
students.add( new Student2("Alex" , 22 , "male" , 100D) );//成绩重复,插入失败
for (Student2 s : students) {//实现Comparable接口才能排序,且自定义排序规则
System.out.println(s.toString());
}
}
}
class Student2 implements Comparable<Student2>{
String name;
Integer age;
String sex;
Double score;
public Student2(String name, Integer age, String sex, Double score) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
}
@Override
public int compareTo(Student2 o) {//降序
if(o.score > this.score) {//this小,就靠后
return 1;
}else if(o.score < this.score){
return -1;
}
return 0;
}
@Override
public String toString() {
return "Student2 [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score + "]";
}
}
输出结果:
Student2 [name=Anine, age=21, sex=female, score=100.0]
Student2 [name=Tom, age=20, sex=male, score=99.0]
Student2 [name=Rose, age=19, sex=female, score=95.0]
Student2 [name=Jack, age=23, sex=male, score=92.0]