集合框架(3):set | HashSet | LinkedHashSet | TreeSet的底层源码

    技术2022-07-11  65

    目录

    一、Set练习题:在list内去除重复数据值。 二、HashSet三、LinkHashSet四、TreeSet1.自然排序2.定制排序


    如果对List及其子实现类底层感兴趣的可以看这篇文章:List | ArrayList | LinkedList | Vector的底层源码

    一、Set

    1.Set接口的框架结构:存储无顺序的,不可重复的数据。

    HashSet:作为set接口的主要实现类,线程不安全,可以存储null值。底层为数组+链表。LinkedHashSet:作为HashSet的子类。遍历其内部数据时,可以按照添加的顺序遍历。 对于频繁遍历的操作,LinkedHashSet的效率高于HashSet。TreeSet:采用红黑树的存储结构,可以按照添加对象的指定属性,进行排序。

    2.如何理解Set的无序,不可重复。 以HashSet为例说明: ①无序性:不等于随机性。 存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值添加。 ②不可重复性:保证添加的元素按照equals()方法判断时,不能返回true。即,相同的元素只能添加一个。

    3.Set接口中没有额外定义新的方法,使用的都是Collection接口中声明过的方法。

    4.添加元素的过程:以HashSet为例:

    我们像HashSet中添加元素a,首先调用元素a所在类的hashcode方法,计算a的哈希值, 此哈希值通过某种算法计算中在HashSet底层数组的存放位置(即:索引位置), 判断数组此位置是否已经有元素: 如果此位置上没有其他元素,则元素a直接添加成功。---情况1 如果此位置有其他元素b(或以链表形式存在多个元素),则比较a和b的哈希值: 如果哈希值不相同,则元素a添加成功。 ---情况2 如果哈希值相同,则调用元素a所在类的equals()方法: equals()返回true,元素添加失败。 equals()返回返回false,则元素a添加成功。 ---情况3

    说明:对于添加成功的情况2和情况3而言:元素a与已经存在指定位置上数据以链表方式存。 jdk7中:元素a放到数组中,指向原来的元素。 jdk8中原来的元素放在数组中,指向a元素。

    5.要求: ①向Set中添加的数据,其所在的类一定要重写hashCode()和equals()方法 ②重写hashCode()和equals()方法尽可能保持一致:相等的对象必须具有相等的哈希值。

    练习题:在list内去除重复数据值。

    public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("123"); list.add("456"); list.add("789"); list.add("456"); List list2=duplicateList(list); Iterator<String> iterator = list2.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next ()); } } public static List<String> duplicateList(List list){ HashSet<String> set = new HashSet<>(); set.addAll(list); return new ArrayList(set); }

    二、HashSet

    添加元素的过程:以HashSet为例:

    我们像HashSet中添加元素a,首先调用元素a所在类的hashcode方法,计算a的哈希值, 此哈希值通过某种算法计算中在HashSet底层数组的存放位置(即:索引位置), 判断数组此位置是否已经有元素: 如果此位置上没有其他元素,则元素a直接添加成功。---情况1 如果此位置有其他元素b(或以链表形式存在多个元素),则比较a和b的哈希值: 如果哈希值不相同,则元素a添加成功。 ---情况2 如果哈希值相同,则调用元素a所在类的equals()方法: equals()返回true,元素添加失败。 equals()返回返回false,则元素a添加成功。 ---情况3

    三、LinkHashSet

    1.LinkedHashSet的使用: LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了一对双向链表,记录此数据的前一个数据和后一个数据。

    2.优点: 对于频繁遍历的操作,LinkedHashSet的效率高于HashSet。

    四、TreeSet

    1.自然排序

    1.向TreeSet中添加的数据,要求是同一个类的对象,不能添加不同类的对象。 2.两种排序方式:自然排序(实现Comparable接口)和定制排序(实现Comparator接口) 3.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()

    代码实现:

    @Test public void test1(){ TreeSet set = new TreeSet(); //举例1: set.add(34); set.add(-25); set.add(77); set.add(8); Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("*************举例2*****************"); TreeSet set1 = new TreeSet(); set1.add(new User("Tom",22)); set1.add(new User("Jerry",24)); set1.add(new User("BeiBei",21)); set1.add(new User("DongDong",20)); set1.add(new User("MM",53)); set1.add(new User("MM",18)); Iterator iterator1 = set1.iterator(); while (iterator1.hasNext()){ System.out.println(iterator1.next()); } } } public class User implements Comparable{ private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } 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 boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(name, age); } //按照姓名从大到小排序,年龄从小到大排序, @Override public int compareTo(Object o) { if (o instanceof User){ User user= (User) o; int num= this.name.compareTo(user.name); if (num!=0){ return -num; }else{ return Integer.compare(this.age,user.age); } }else{ throw new RuntimeException("类型不一致!"); } } }

    2.定制排序

    定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals()。

    代码实现:

    @Test public void test2(){ Comparator comparator = new Comparator(){ //按照年龄从小到大排序 @Override public int compare(Object o1, Object o2) { if (o1 instanceof User && o2 instanceof User){ User d1= (User) o1; User d2= (User) o2; return Integer.compare(d1.getAge(),d2.getAge()); }else{ throw new RuntimeException("类型不一致!"); } } }; TreeSet set = new TreeSet(comparator); set.add(new User("Tom",22)); set.add(new User("Jerry",24)); set.add(new User("BeiBei",21)); set.add(new User("DongDong",20)); set.add(new User("Mary",18)); set.add(new User("MM",18)); Iterator<Object> iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } }
    如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发 创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
    Processed: 0.011, SQL: 9