1. Set集合
Set集合不允许包含相同的元素
,如果试把同个相同的元素加入同一个Set集合中,则添加操作失败。- Set判断两个对象是否相同不是使用==运算符,而是
根据equals方法
2. HashSet
- HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。
- HashSet按
Hash算法
来存储集合中的元素,因此具有很好的存取和查找性能。 - HashSet具有以下特点:
不能保证元素的排列顺序
HashSet不是线程安全的
集合元素可以使用null
- 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置。
- 如果两个元素的equals()方法返回true,但它们的hashCode()返回值不相等,HashSet将会把他们存储在不同的位置,但依然可以添加成功。
- HashSet 由 HashMap 来定义
- 在HashSet中维护了一个HashMap属性
- 在调用HashSet的方法时,实际操作的是HashMap的对应的方法
- add(Object obj)实际上是吧obj放入了map中:
public boolean add(E e){
return map.put(e, PRESENT) == null;
}
public boolean contains(Object o){
return map.containsKey(o)
}
package test.com.atguigu.javase.lesson7;
import com.atguigu.javase.lesson7.Person;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
/**
* 关于HashSet
* 1、HashSet是Set的最典型实现
* 2、HashSet中不能有重复的元素。判定两个元素相等的标准,equals()方法返回true
* 3、HashSet根据hashCode()值来存放元素,所以不能保证元素的顺序
*/
public class HashSetTestTest {
@Test
public void testAdd(){
Person p1 = new Person("AA",12);
Person p2 = new Person("AA",12);
System.out.println(p1.equals(p2));
System.out.println(p2.equals(p1));
Set set = new HashSet();
set.add(p1);
set.add(p2);
System.out.println(set.size());//1
}
}
3. hashCode()方法
- HashSet集合判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
如果两个对象通过equals()方法返回true,这两个对象的hashCode值也应该相同
- 重写hashCode()方法的基本原则
- 在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值
- 当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值也应相等
- 对象中用作equals()方法比较的Field,都应该用来计算hashCode值
/**
* 为什么在hashCode方法中有质数的存在
*
* Person p1:name的hashCode值为1000,age的hashCode为22
* Person p1:name的hashCode值为22,age的hashCode为1000
* @return
*/
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
return result;
}
4. LinkedHashSet
- LinkedHashSet是HashSet的子类。
- LinkedHashSet集合根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
- LinkedHashSet性能:插入性能略低于HashSet,但在迭代访问Set里的元素时有很好的性能。
- LinkedHashSet不允许集合元素重复。
package com.atguigu.javase.lesson7;
import org.junit.Test;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
public class LinkedHashSetTest {
@Test
public void test(){
Collection collection = new LinkedHashSet();
collection.add(new Person("AA",12));
collection.add(new Person("BB",12));
collection.add(new Person("CC",12));
collection.add(new Person("DD",12));
collection.add(new Person("EE",12));
Iterator iterator = collection.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
5. TreeSet
- TreeSet是SortedSet接口的实现类,
TreeSet可以确保集合元素处于排序状态
- Comparator comparator()
- Object first()
- Object last()
- Object lower(Object e)
- Object higher(Object e)
- SortedSet subSet(fromElement, toElement)
- SortedSet headSet(toElement)
- SortedSet tailSet(fromELement)
- TreeSet支持两种排序方法,自然排序和定制排序。默认情况下,TreeSet采用自然排序。
6. 自然排序
- 排序:
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列
如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口
- 实现Comparable的类必须实现compareTo(Object obj)方法,两个对象即通过compareTo(Object obj)方法的返回值来比较大小
- Comparable的典型实现:
- BigDecimal、BigInteger以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
- Character:按字符的UNICODE值来进行比较
- Boolean:true对应的包装类实例大于false对应的包装类实例
- String:按字符串中字符的UNICODE值进行比较
- Date、Time:后边的时间、日期比前面的时间、日期大
- 因为只有相同类的两个实例才会比较大小,所以向TreeSet中添加的应该是同一个类的对象
- 当需要把一个对象放入TreeSet中,重写该对象对应的equals()方法时,应保证该方法与compareTo(Object obj)方法有一致的结果:如果两个对象通过equals()方法比较返回true,则通过compareTo(Object obj)方法比较应该返回0
7.示例代码
Person类
package com.atguigu.javase.lesson7;
public class Person implements Comparable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age;
}
@Override
public int hashCode() {
return age;
}
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person person = (Person)o;
//return this.name.compareTo(person.name);
return this.age - person.age;
}else{
throw new ClassCastException("不能转为Person类型");
}
}
}
TreeSetTest类
package test.com.atguigu.javase.lesson7;
import com.atguigu.javase.lesson7.Person;
import org.junit.Test;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
/**
* testTreeSetWithComparable.
*
* 1.默认情况下TreeSet要求集合中的元素必须实现Comparable接口
* Comparable接口中只有一个方法:
* publi int compareTo(T o)
* 若返回0,代表两个元素相等。
* 若放回负数,代表当前元素小。
* 若返回整数,代表当前元素大。
*
* TreeSet会调用每个元素的compareTo()方法去和集合中的每个已经有的元素去比较,进而
* 决定当前元素在集合中的位置。
*
*/
@Test
public void testTreeSetWithComparable(){
TreeSet set = new TreeSet();
set.add(new Person("AA",12));
set.add(new Person("CC",13));
set.add(new Person("EE",14));
set.add(new Person("DD",15));
set.add(new Person("BB",16));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
7. 练习
Student类
package com.atguigu.javase.lesson7;
/**
* Created by xie on 2018/7/4.
*/
public class Student implements Comparable {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Student){
Student student = (Student)o;
return student.score - this.score;
}else{
throw new ClassCastException("不能转为Student类型");
}
}
}
TreeSet类
package com.atguigu.javase.lesson7;
import java.util.Iterator;
import java.util.Scanner;
public class TreeSet {
public static void main(String args[]) {
/**
* 练习:
* 新建一个Student类,包含:studentName,score
* 利用Scanner对象输入5个学生的信息
*
* student1 name: Tom
* student1 score: 500
*
* ......
*
* student5 name:Jerry
* student5 score:440
*
* 把学生信息放入到TreeSet中,利用Comparable的方式来排序
* 按分数降序输出学生信息
*/
//1.创建一个TreeSet对象
java.util.TreeSet set = new java.util.TreeSet();
//2.由控制台输入5个学生的信息,并把每个学生的对象放入TreeSet中
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < 5; i++) {
System.out.print("第 " + (i + 1) + "个学生的name:");
String name = scanner.next();
System.out.print("第 " + (i + 1) + "个学生的score:");
int score = scanner.nextInt();
Student student = new Student(name, score);
set.add(student);
}
//3.遍历TreeSet打印即可
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
8. 定制排序
如果需要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator接口的实现类对象。由该Comparator对象负责集合元素的排序逻辑。
public TreeSet(Comparator< ? super E> comparator)
Method summary
int compare(T o1, T o2): Compares its two arguments for order
boolean equals(Object obj): Indicates whether some other object is “equal to” this comparator
Person1类
package com.atguigu.javase.lesson7;
public class Person1{
private String name;
private int age;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public Person1() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
TreeSetTest类:
package test.com.atguigu.javase.lesson7;
import com.atguigu.javase.lesson7.Person;
import com.atguigu.javase.lesson7.Person1;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
@Test
public void testTreeSetWithComparator(){
//1.创建Comparator接口的实现类对象
//实现compare(Object o1, Object o2)来比较两个对象的大小
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Person1 && o2 instanceof Person1){
Person1 p1 = (Person1)o1;
Person1 p2 = (Person1)o2;
return p1.getAge() - p2.getAge();
}else{
throw new ClassCastException("不能转为Person类型");
}
}
};
//2.创建TreeSet对象,传入Comparator接口的实现类对象
TreeSet set = new TreeSet(comparator);
set.add(new Person1("AA",12));
set.add(new Person1("CC",13));
set.add(new Person1("EE",14));
set.add(new Person1("DD",15));
set.add(new Person1("BB",16));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}