JDK1.8-API在线中文版
1. Set接口与实现类
特点:
1)无序、无下标、元素不可重复(当插入新元素时,如果新元素与已有元素进行equals比较,结果为true时,则拒绝新元素插入)
2)set接口并没有提供自己独有的方法,均是继承Collection的方法
Set 注重独一无二的性质,该体系集合用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。对象的相等性本质是对象 hashCode 值(java 是依据对象的内存地址计算出的此序号)判断的,如果想要让两个不同的对象视为相等的,就必须覆盖 Object 的 hashCode 方法和 equals 方法。
元素不重复的基本逻辑判断示意图:
包装类型,重写hashCode就很简单:
class Student{
String name;
Integer age;
String sex;
Double score;
// ...
@Override
public int hashCode() {
return (this.name.hashCode() + this.sex.hashCode() + this.age.hashCode() + this.score.hashCode());
}
}
基本类型,重写hashCode详解:【Java】如何重写hashCode()和equals()方法
Set接口的实现类:HashSet、LinkedHashSet、TreeSet
① HashSet类(基于HashCode-无序)
特点:
- 基于HashCode实现元素不重复 - 无序
- 当存入元素的哈希码相同时,会调用equals确认,结果为true,则拒绝后者加入
- 无参构建初始容量为16(负载因子0.75,即+75%容量扩容)
- 底层使用的HashMap类,即将所有需要存储的值,通过HashMap去重存入
- 先判断hashCode是否相同,再==比较地址是否相同,再equals内容是否相同
import java.util.HashSet;
import java.util.Set;
public class TestHashSet3 {
public static void main(String[] args) {
Student s1 = new Student("tom", 20, "male", 99.0); // 0x0000 1111
Student s2 = new Student("jack", 23, "male", 88.0);
Student s3 = new Student("mark", 22, "male", 95.0);
Student s4 = new Student("anna", 21, "female", 93.0);
Student s5 = new Student("tom", 20, "male", 99.0); // 0x0000 2222
Set students = new HashSet(); // 快速导包:Ctrl+Shift+O
students.add(s1); // 0x0000 1111
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s1); // 0x0000 1111, add失败,去掉了重复:equals--->Object类提供的(this==obj)判断
students.add(s5); // 0x0000 2222(内容相同,地址不同)也需要去重
for (Student student : students) {
System.out.println(student.toString());
}
/*
* 注意:HashSet没有必要在每次插入一个新值时对数据都去一一比较
* 注意:HashSet调用equals方法进行比较,是具有前提的(两个对象的哈希码相同)
*/
System.out.println(s1.equals(s5));
}
}
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;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score + "]";
}
@Override
public boolean equals(Object obj) {
System.out.println("Student's equals() method executed...");
if (this == obj) { return true; }
if (null == obj) { return false; }
if (this.getClass() != obj.getClass()) { return false; }
Student s = (Student)obj;
if (this.toString().equals(s.toString())) {
return true;
}
return false;
}
@Override
public int hashCode() {
return (this.name.hashCode() + this.sex.hashCode() + this.age.hashCode() + this.score.hashCode());
}
}
② LinkedHashSet类(记录插入顺序)
特点:
- 继承自HashSet,又基于LinkedHashMap来实现的
- 底层使用LinkedHashMap(链表结构)存储,节点形式独立存储数据,并可以指向下一个节点,通过顺序访问节点,可保留元素的插入顺序 - 插入顺序
- 所有方法与HashSet相同,用法也一模一样
import java.util.LinkedHashSet;
public class TestLinkedHashSet {
public static void main(String[] args) {
// 底层使用LinkedHashMap(链表结构)存储,节点形式完成单独数据的保存
// 并可以指向下一个节点,通过顺序访问节点,可保留元素的插入顺序
LinkedHashSet set = new LinkedHashSet();
set.add("aa");
set.add("bb");
set.add("cc");
set.add("dd");
set.add("ee");
for (String s : set) {
System.out.print(s + " ");
}
System.out.println();
LinkedHashSet lhs = new LinkedHashSet();
lhs.add(11);
lhs.add(99);
lhs.add(66);
lhs.add(33);
lhs.add(55);
lhs.add(44);
for (Integer i : lhs) {
System.out.print(i + " ");
}
}
}
③ TreeSet类(二叉树-自动排序)
特点:
- 基于排列顺序实现元素不重复 - 自动排序
- 实现了SortedSet接口,对所有插入集合的元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则(Integer/String类默认实现),通过重写CompareTo方法才能使用,以确定是否为重复元素
import java.util.TreeSet;
public class TestTreeSet2 {
public static void main(String[] args) {
TreeSet stus = new TreeSet();
stus.add(new Student("tom", 20, "male", 80.0));
stus.add(new Student("jak", 20, "male", 90.0));
stus.add(new Student("vae", 20, "male", 100.0));
stus.add(new Student("com", 20, "male", 60.0));
for (Student student : stus) {
System.out.println(student.toString());
}
}
}
class Student implements Comparable{
String name;
Integer age;
String sex;
Double score;
public Student() {
super();
}
public Student(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(Student o) {
//主要排序列
if (this.score < o.score) {
return -1;
} else if (this.score > o.score){
return 1;
} else {
//次要排序列(排序的属性中可能是个多属性的对象)
if (this.age < o.age) {
return -1;
} else if (this.age > o.age) {
return 1;
}
}
return 0;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", score=" + score + "]";
}
}
2. HashSet排序的两种方法
1)遍历加入到List中使用Collections.sort(list)排序;
2)使用TreeSet的构造创建一个TreeSet对象实现自动排序;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.TreeSet;
public class TestHashSetSort {
public static void main(String[] args) {
/* 对HashSet排序的两种办法验证 */
HashSet numSet = new HashSet();
numSet.add(55);
numSet.add(11);
numSet.add(66);
numSet.add(88);
numSet.add(33);
System.out.println(numSet); // [33, 66, 55, 88, 11]
System.out.println("------------------------");
sortByTreeSet(numSet); // [11, 33, 55, 66, 88]
System.out.println("------------------------");
sortByList(numSet); // [11, 33, 55, 66, 88]
}
// 装进TreeSet里,自动排序
public static void sortByTreeSet(HashSet set) {
TreeSet numTree = new TreeSet(set);
System.out.println(numTree);
}
// 装进ArrayList里,通过sort排序
public static void sortByList(HashSet set) {
List numList = new ArrayList();
for (Integer i : set) {
numList.add(i);
}
Collections.sort(numList);
System.out.println(numList);
}
}