Java基础学习总结:集合之(三)Set、HashSet、TreeSet

一、Set

(1)Set简介

Set接口是单列集合(Collection)的另一个重要的分支,Set集合中元素无序且不可重复,不能通过下标访问。HashSet 和 TreeSet 是 Set 接口的两个实现类。

(2)常用方法

方法描述

add(E e)

确保此 collection 包含指定的元素(可选操作)。

addAll(Collection<? extends E> c)

将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。

clear()

移除此 collection 中的所有元素(可选操作)。

contains(Object o)

如果此 collection 包含指定的元素,则返回true

containsAll(Collection<?> c)

如果此 collection 包含指定 collection 中的所有元素,则返回 true

equals(Object o)

比较此 collection 与指定对象是否相等。

isEmpty()

如果此 collection 不包含元素,则返回true

iterator()

返回在此 collection 的元素上进行迭代的迭代器。

remove(Object o)

从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。

removeAll(Collection<?> c)

移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。

retainAll(Collection<?> c)

仅保留此Collection中那些也包含在指定 Collection 的元素

size()

返回此Collection中元素的位数

toArray()

返回包含此Collection中所有元素的数组

因为 List 和 Set 都实现了Collection 接口,所以两类集合中的方法基本都是从父类中继承过来的,所以 用法基本相同。

二、HashSet

(1)简介

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{}

HashSet继承了AbstractSet类,并实现了Set接口、Cloneable接口 和 Serializable接口。

实现原理:hash表(数组+链表)。

HashSet不允许集合中出现重复元素。当我们提到HashSet时,第一件事就是在将对象存储在HashSet之前,要确保重写hashCode()方法和equals()方法,这样才能比较对象的值是否相等,确保集合中没有储存相同的对象。如果不重写上述两个方法,那么将使用下面方法默认实现:

public boolean add(Object obj)方法用在Set添加元素时,如果元素值重复时返回 "false",如果添加成功则返回"true"。

(2)HashSet的构造方法(5个):

/**
 * 默认的无参构造器,构造一个空的HashSet。
 *
 * 实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。
 */
public HashSet() {
    map = new HashMap<E,Object>();
}

/**
 * 构造一个包含指定collection中的元素的新set。
 *
 * 实际底层使用默认的加载因子0.75和足以包含指定collection中所有元素的初始容量来创建一个HashMap。
 * @param c 其中的元素将存放在此set中的collection。
 */
public HashSet(Collection<? extends E> c) {
    map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

/**
 * 以指定的initialCapacity和loadFactor构造一个空的HashSet。
 *
 * 实际底层以相应的参数构造一个空的HashMap。
 * @param initialCapacity 初始容量。
 * @param loadFactor 加载因子。
 */
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<E,Object>(initialCapacity, loadFactor);
}

/**
 * 以指定的initialCapacity构造一个空的HashSet。
 *
 * 实际底层以相应的参数及加载因子loadFactor为0.75构造一个空的HashMap。
 * @param initialCapacity 初始容量。
 */
public HashSet(int initialCapacity) {
    map = new HashMap<E,Object>(initialCapacity);
}

/**
 * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。此构造函数为包访问权限,不对外公开,
 * 实际只是是对LinkedHashSet的支持。
 *
 * 实际底层会以指定的参数构造一个空LinkedHashMap实例来实现。
 * @param initialCapacity 初始容量。
 * @param loadFactor 加载因子。
 * @param dummy 标记。
 */
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}

(3)HashSet的使用

新建一个 Student 类,并重写 hashcode() 和 equals() 方法。

package basis.CollectionStu;

import java.util.Objects;

public class Student {
    private String name;
    private int age;
    private String phone;

    public Student(String name, int age, String phone) {
        this.name = name;
        this.age = age;
        this.phone = phone;
    }
    public Student() {

    }

    //省略getter和setter
    //重写hashcode()和equals()方法

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return getAge() == student.getAge() &&
                Objects.equals(getName(), student.getName()) &&
                Objects.equals(getPhone(), student.getPhone());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge(), getPhone());
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                '}';
    }
}

主类:

package basis.CollectionStu;

import java.util.HashSet;
import java.util.Iterator;

public class StuHashSet {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet();
        //添加
        Student student_1 = new Student("suxing",21,"11111");
        Student student_2 = new Student("lisi",22,"222222");
        Student student_3 = new Student("zhangsan",23,"333333");
        students.add(student_1);
        students.add(student_2);
        students.add(student_3);
        students.add(student_1);

        //遍历
        Iterator<Student> it = students.iterator();
        while (it.hasNext()){
            System.out.println(it.next().toString());
        }
    }
}

输出结果:

Student{name='zhangsan', age=23, phone='333333'}
Student{name='suxing', age=21, phone='11111'}
Student{name='lisi', age=22, phone='222222'}

结果表明:输出顺序跟我们插入的顺序并不一致,可见,重写了hashcode()方法和equals()方法,实现了元素重排。并且相同的对象不能再次插入到集合中。

三、TreeSet

(1)简介

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{}
  • TreeSet继承了AbstractSet抽象类,所以它是一个set集合,可以被实例化,且具有set的属性和方法,并实现了Cloneable接口、NavigableSet接口 和 Serializable接口。
  • TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
  • TreeSet的性能比HashSet差但是我们在需要排序的时候可以用TreeSet因为他是自然排序也就是升序下面是TreeSet实现代码这个类也似只能通过迭代器迭代元素

(2)构造方法

    //默认无参构造
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    //传入一个指定的比较器
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

    //传入一个指定的Collection,使新的TreeSet包含此Collection中的所有元素
    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }

    //传入一个SortedSet    
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

 SortedSet是Set的一个子接口:

public interface SortedSet<E> extends Set<E> {}

(3)TreeSet的使用

TreeSet有两种排序方法:自然排序和定制排序。默认采用自然排序。

要求自定义类实现java.lang.Comparable接口并重写其compareTo(Object obj)的抽象方法在此方法中,指明按照自定义类的哪个属性进行排序。向TreeSet中添加元素时,首先按照compareTo()进行比较,一旦返回0,虽然仅是两个对象的此属性值相同,但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来。因此要求compareTo()与hashCode()以及equals()三者保持一致!

定义一个Person 类,实现compareable 接口,重写 compareTo() 方法。

package basis.CollectionStu;

public class Person implements Comparable {
    private String name;
    private int age;
    private String phone;

    public Person() {}

    public Person(String name, int age, String phone) {
        this.name = name;
        this.age = age;
        this.phone = phone;
    }

    //省略getter和setter

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        Person person  = (Person) o;
        //根据年龄进行比较
        return this.age>person.age?1:(this.age==person.age?0:-1);
    }
}

 主类:

package basis.CollectionStu;

import java.util.Iterator;
import java.util.TreeSet;

public class StuTreeSet {
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet();
        //添加
        Person person_1 = new Person("suxing",23,"11111");
        Person person_2 = new Person("lisi",21,"22222");
        Person person_3 = new Person("wangwu",20,"33333");
        Person person_4 = new Person("zhaoliu",23,"44444");

        persons.add(person_1);
        persons.add(person_2);
        persons.add(person_3);
        persons.add(person_4);

        //遍历
        Iterator<Person> it = persons.iterator();
        while (it.hasNext()){
            System.out.println(it.next().toString());
        }
    }
}

运行结果:

Person{name='wangwu', age=20, phone='33333'}
Person{name='lisi', age=21, phone='22222'}
Person{name='suxing', age=23, phone='11111'}

由结果可以看出,实现compareable 接口,重写 compareTo() 方法,实现了集合中的元素按照指定的方法进行排序,而且年龄重复的元素不再插入到集合中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值