java加强 -Set集合

Set集合是Collection集合下的一个分支。

特点:无序;添加数据的顺序和取出的顺序不一致;不重复;无索引;

Set集合具有三个常见的实现类:

1、HashSet:无序、不重复、无索引

2、LinkedHashSet:有序、不重复、无索引

3、TreeSet:排序、不重复、无索引

示例

package HashSetDemo;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

public class SetDemo1 {
    //目标:认识Set家族集合的特点
    //Set的常用方法基本就是Collection提供的,几乎没有新增的常用方法
    public static void main(String[] args) {
        //1、创建一个Set集合
        //HashSet无序、不重复、无索引
        //Set<String> set = new HashSet<>();
        //LinkedHashSet有序、不重复、无索引
        Set<String> set = new LinkedHashSet<>();
        set.add("大数据");
        set.add("java");
        set.add("java");
        set.add("c++");
        set.add("python");
        set.add("java");
        set.add("鸿蒙");
        System.out.println(set);
        //2、创建一个TreeSet集合,排序(默认按升序排序),不重复,无索引
        Set<Double> set1 = new TreeSet<>();
        set1.add(3.14);
        set1.add(2.14);
        set1.add(1.14);
        set1.add(4.14);
        set1.add(3.14);
        System.out.println(set1);
        System.out.println("===========================");
        //哈希值是一个随机返回的值
        //用hashCode方法获取对象的哈希值
        //hashCode方法返回值是一个int类型的值,所以可以作为int类型的数组下标
        //同一个对象的哈希值是相同的
        String s1="java";
        String s2="python";
        System.out.println(s1.hashCode());
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s2.hashCode());
    }
}

HashSet集合根据哈希值来判断两个数据是否相同。哈希值是一个int类型的随机值,Java中每个数据都有其对应的哈希值,Java中的所有对象,都可以用Object类提供的hashCode方法,返回该对象的哈希值。

对象哈希值的特点

同一个对象多次调用hashCode()方法返回的哈希值是相同的。不同的对象,他们的哈希值大概率不相等,但也有可能相等(哈希碰撞)。

HashSet集合的底层原理

基于哈希表实现

1、创建一个长度为16的默认长度的数组,默认加载因子为0.75,数组名table。

2、用元素的哈希值对数组的长度做运算计算出应存入的位置。

3、判断当前位置是否是null,如果是null直接存入

4、如果不为null,用equals方法判断是否相同,如果相同不存入,不相同则存入数组。

JDK8以前的哈希表:数组加链表,新元素若是与老元素计算到了一个位置,新元素占老元素位置,老元素挂新元素下。JDK8以后,新元素直接挂老元素下。

当总长度达到当前长度乘加载因子的数量时,开始扩展数组,直接翻一倍。

JDK8开始,链表长度大于8(一个元素下挂着8个以上元素),且数组长度大于等于64,自动将链表转换为红黑树(左边比根节点小,右边比根节点大)。

当存入的类型为自定义对象时,因为类对象虽然内容相同,但本质上是不同的对象,因此会导致其哈希值不同,重复存入HashSet数组,此时需要在类内重写equals方法和hashCode方法进行去重(或使用@Data,其不仅有getset方法,还重写了equals和hashCode等方法)。

package HashSetDemo;

import java.util.Objects;

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

    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;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
    //重写HashCode方法和equals方法用于去重

    //两个对象内容一样结果为true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;//自己和自己比,直接true
        //如果o 为空 或者 o 的类型和当前对象不一样,返回false
        if (o == null || this.getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name) && Objects.equals(address, student.address) && Objects.equals(phone, student.phone);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, address, phone);
    }

    @Override
    public String toString() {
        return "name:"+name+" "+"age:"+age+" "+"address:"+address+" "+"phone:"+phone;
    }
}
package HashSetDemo;

import java.util.HashSet;
import java.util.Set;

public class SetDemo2 {
    public static void main(String[] args) {
        //掌握HashSet的去重操作
        Student s1 = new Student(18,"北京","张三","123456");
        Student s2 = new Student(18,"北京","李四","989893");
        Student s3 = new Student(18,"北京","张三","123456");
        Student s4 = new Student(18,"北京","李四","989893");
        //无法判断是否重复,因为虽然对象内的成员变量相同,但是返回的哈希值不同,所以无法去重
        //通过重写结构体内的hashcode和equals方法,使得两个对象返回的hashcode值相同,从而实现去重
        Set<Student> set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        System.out.println(set);
    }
}

TreeSet对自定义对象的排序

1、对象类实现一个Comparable接口,重写compare方法,指定大小比较规则

2、public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则

package HashSetDemo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Teacher implements Comparable<Teacher>{
    private String name;
    private int age;
    private double salary;
    @Override
    public String toString()
    {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}'+"\n";
    }
    //t2.compareTo(t1)
    //t2==this 比较者
    //t1==o 被比较者
    //规定:如果t2大于t1,返回正数;如果t2小于t1,返回负数;如果t2等于t1,返回0
    @Override
    public int compareTo(Teacher o) {
        //按照年龄升序排序
//            if (this.age>o.age)
//                return 1;
//            else if (this.age<o.age)
//                return -1;
//            return 0;
//    }
        return this.age-o.age;//升序
        //return o.age-this.age;//降序
    }
}
package HashSetDemo;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class SetDemo3 {
    public static void main(String[] args) {
        //TreeSet对于自定义对象的排序
        Set<Teacher> teachers= new TreeSet<>();     //排序、去重、无索引
        //没有默认的排序规则,所以需要重写compareTo方法
        teachers.add(new Teacher("老陈", 30, 5000));
        teachers.add(new Teacher("小王", 27, 6300));
        teachers.add(new Teacher("小李", 29, 5200));
        teachers.add(new Teacher("小张", 27, 3200));
        //解决方案
        //1、对象类实现一个Comparable接口,重写compare方法,指定大小比较规则
        //2、public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则
        System.out.println(teachers);
        //优先使用匿名内部类里的规则
        Set<Teacher> teachers1 = new TreeSet<>(new Comparator<Teacher>() {
//            @Override
//            public int compare(Teacher o1, Teacher o2) {
//                return o2.getAge()-o1.getAge();//年龄降序
//            }
            //薪水升序
            @Override
            public int compare(Teacher o1, Teacher o2) {
                return Double.compare(o1.getSalary(),o2.getSalary());
            }
        });
        teachers1.add(new Teacher("老陈", 30, 5000));
        teachers1.add(new Teacher("小王", 28, 630));
        teachers1.add(new Teacher("小李", 29, 5200));
        teachers1.add(new Teacher("小张", 27, 3200));
        System.out.println(teachers1);

    }
}

如果希望记住元素的添加顺序,存储重复的元素,需要频繁的查找数据,使用ArrayList集合(基于数组)。

如果希望记住元素的添加顺序,且首尾增删情况较多,应使用LinkedList集合(基于双链表)。

不在意元素顺序,没有元素需要重复存储,只希望增删改查能快,用HashSet集合(基于哈希表)。

希望记住元素的添加顺序,没有重复元素需要存储,且希望增删改查都快,用LinkedHashSet集合(基于哈希表和双链表)。

要对元素进行排序,没有重复元素需要存储,希望增删改查都快,使用TreeSet集合(基于红黑树)。

以上均为理想情况,应用时需要具体情况具体分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值