Java Collection接口的子接口之Set接口及其Set接口的主要实现类HashSet,LinkedHashSet,TreeSet详解(二)

简介: Java Collection接口的子接口之Set接口及其Set接口的主要实现类HashSet,LinkedHashSet,TreeSet详解

HashSet的课堂练习题如下

具体代码如下

public class HashSetExercise {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("tom", 20));
        hashSet.add(new Employee("jack", 19));
        hashSet.add(new Employee("tom", 20));
        System.out.println(hashSet);
    }
}
class Employee {
    private String name;
    private int age;
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }
//如果name和age相同,则返回相同的hash值
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Objects.equals(name, employee.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

输出结果如下

[Employee{name='tom', age=20}, Employee{name='jack', age=19}]

六、LinkedHashSet的使用

1、LinkedHashSet的全面说明

2、LinkedHashSet底层机制示意图

3、LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据

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

@Test
    public void SetTest(){
        Set hashSet = new LinkedHashSet();
        hashSet.add("hello");
        hashSet.add("AA");
        hashSet.add(12);
        hashSet.add(12);
        hashSet.add("cc");
        hashSet.add(new User("小红",13));
        hashSet.add(new User("小红",13));
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

遍历的结果:是按照添加的顺序,进行遍历的。

hello

AA

12

cc

www.entity.User@168edbb

LinkedHashSet底层源码分析

@SuppressWarnings({"all"})
public class LinkedHashSetResource {
    public static void main(String[] args) {
        //分析一下LinkedHashSet的底层机制
        Set set = new LinkedHashSet();
        set.add(new String("AA"));
        set.add(456);
        set.add(456);
        set.add(new Customer("刘", 1001));
        set.add(123);
        set.add("ly");
        System.out.println("set=" + set);
        //1.LinkedHashSet 加入顺序和取出元素/数据的顺序一致
        //2.LinkedHashSet底层维护的是一个LinkedHashMap(是HashMap的子类)
        //3.LinkedHashSet底层结构(数组+双向链表)
        //4.添加第一次时,直接将数组table扩容到16,存放的结点类型是LinkedHashMap$Entry
        //5.数组是HashMap$Node[]存放的元素/数据是LinkedHashMap$Entry类型
        /*
        //继承关系是在内部类完成
        static class Entry<K,V> extends HashMap.Node<K,V> {
            Entry<K,V> before, after;
            Entry(int hash, K key, V value, Node<K,V> next) {
                super(hash, key, value, next);
            }
        }
         */
    }
}
class Customer {
    private String name;
    private int no;
    public Customer(String name, int no) {
        this.name = name;
        this.no = no;
    }
    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", no=" + no +
                '}';
    }
}

输出结果如下

set=[AA, 456, Customer{name='刘', no=1001}, 123, ly]

LinkedHashSet对应的练习题

具体代码如下

public class LinkedHashSetExercise {
    public static void main(String[] args) {
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add(new Car("奥迪", 10000));
        linkedHashSet.add(new Car("保时捷", 1000000));
        linkedHashSet.add(new Car("奥迪", 10000));
        System.out.println("linkedHashSet=" + linkedHashSet);
    }
}
class Car {
    private String name;
    private double price;
    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
    //重写equals方法,和hashCode
    //当name和price相同时,就返回相同的hashCode,equals返回true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return Double.compare(car.price, price) == 0 &&
                Objects.equals(name, car.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, price);
    }
}

输出结果如下

linkedHashSet=[Car{name='奥迪', price=10000.0}, Car{name='保时捷', price=1000000.0}]

TreeSet类的详解

TreeSet最大的特点就是可以排序,具体案例代码如下

public class TreeSet_ {
    public static void main(String[] args) {
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的
        //2.希望添加的元素,按照字符串大小来排序
        //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //并制定排序规则
        //简单看看源码
        //源码解读
        /*
        1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator
        public TreeMap(Comparator<? super K> comparator) {
            this.comparator = comparator;
        }
        2.在调用add方法时treeSet.add("tom");,在底层会执行到
        if (cpr != null) {//cpr 就是我们的匿名内部类(对象)
            do {
                parent = t;
                //动态绑定到我们的匿名内部类(对象)compare
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else //如果相等,即返回0,这个Key就没有加入
                    return t.setValue(value);
            } while (t != null);
        }
         */
//        TreeSet treeSet = new TreeSet();
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //下面调用String的compareTo方法 进行字符串大小比较,从小到大排序
//                return ((String) o1).compareTo((String) o2);
                //下面调用String的compareTo方法 进行字符串大小比较,从大到小排序
//                return ((String) o2).compareTo((String) o1);
                //要求加入的元素,按照长度从小到大排序
//                return ((String) o1).length() - ((String) o2).length();
                //要求加入的元素,按照长度从大到小排序
                return ((String) o2).length() - ((String) o1).length();
            }
        });
        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");//字符串长度为3
        treeSet.add("sp");
        treeSet.add("a");
//        treeSet.add("abc");//字符串长度为3 加入不进去 因为长度与 treeSet.add("tom");一致,所以加不进去
        System.out.println("treeset=" + treeSet);
    }
}

输出结果如下

treeset=[jack, tom, sp, a]

四、TreeSet的使用

  1. 向TreeSet中添加的数据,要求是相同类的对象
  2. 两种排序方式:自然排序和定制排序
  3. 自然排序中,比较两个对象是否相同的标准为:CompareTo()返回0,不再是equals
@Test
    public void TreeSetTest(){
        TreeSet set = new TreeSet();
        //失败:不能添加不同类的对象
//        set.add("hello");
//        set.add("AA");
//        set.add(12);
//        set.add(12);
//        set.add("cc");
//        set.add(new User("Tom",13));
        //举例1. Integer类型 按照从小到大的顺序排列
//        set.add(23);
//        set.add(77);
//        set.add(-53);
//        set.add(12);
//        set.add(56);
        //举例2. String类型 按照从小到大的顺序排列
//        set.add("23");
//        set.add("abe");
//        set.add("android");
//        set.add("JAVA");
//        set.add("IOS");
        //举例3. 对象 按照从小到大的顺序排列
        set.add(new User("Tom",13));
        set.add(new User("Jack",23));
        set.add(new User("Mary",15));
        set.add(new User("Jerry",20));
        set.add(new User("Jim",33));
        set.add(new User("Jim",33));
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

User类:

package www.entity;
import java.util.Objects;
public class User implements Comparable {
    private String name;
    private int age;
    @Override
    public boolean equals(Object o) {
        System.out.println("执行了");
        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);
    }
    public User(String name, int age) {
        this.name = name;
        this.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 int compareTo(Object o) {
        if (o instanceof User){
            User user = (User) o;
            int compare = -this.name.compareTo(user.name);
            if (compare!=0){
                return compare;
            }else {
                return Integer.compare(this.age, user.age);
            }
        }else {
            throw new RuntimeException("输入的类型不匹配!");
        }
    }
}

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

@Test
    public void test4() {
        Comparator comparator = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //按照年龄从小到大排序
                if (o1 instanceof User && o2 instanceof User) {
                    User u1 = (User) o1;
                    User u2 = (User) o2;
                    return Integer.compare(u1.getAge(), u2.getAge());
                } else {
                    throw new RuntimeException("输入的数据类型不匹配");
                }
            }
        };
        TreeSet set = new TreeSet(comparator);
        set.add(new User("Tom", 13));
        set.add(new User("Jack", 23));
        set.add(new User("Mary", 15));
        set.add(new User("Jerry", 20));
        set.add(new User("Jim", 33));
        set.add(new User("Toke", 33));
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

输出结果:年龄从小到大排序,如果有相同年龄的,按自上而下的顺序,输出,后面哪个就不再输出。

目录
相关文章
|
JSON Java 关系型数据库
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
在Java中,使用mybatis-plus更新实体类对象到mysql,其中一个字段对应数据库中json数据类型,更新时报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
1540 4
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
214 4
|
Java
那些与Java Set擦肩而过的重复元素,都经历了什么?
在Java的世界里,Set如同一位浪漫而坚定的恋人,只对独一无二的元素情有独钟。重复元素虽屡遭拒绝,但通过反思和成长,最终变得独特,赢得了Set的认可。示例代码展示了这一过程,揭示了成长与独特性的浪漫故事。
120 4
|
Java 开发者
Java Set:当“重复”遇见它,秒变“独宠”!
在Java编程中,Set接口确保集合中的元素不重复,每个元素都是独一无二的“独宠”。本文介绍了Set的两种常见实现:HashSet和TreeSet。HashSet基于哈希表实现,提供高效的添加、删除和查找操作;TreeSet基于红黑树实现,不仅去重还能对元素进行排序。通过示例代码,展示了这两种集合的具体应用,帮助开发者更好地理解和使用Set。
164 4
|
存储 Java 开发者
Java Set:无序之美,不重复之魅!
在Java的集合框架中,Set接口以其“无序之美”和“不重复之魅”受到开发者青睐。Set不包含重复元素,不保证元素顺序,通过元素的hashCode()和equals()方法实现唯一性。示例代码展示了如何使用HashSet添加和遍历元素,体现了Set的高效性和简洁性。
183 4
|
存储 算法 Java
为什么Java Set如此“挑剔”,连重复元素都容不下?
在Java的集合框架中,Set是一个独特的接口,它严格要求元素不重复,适用于需要唯一性约束的场景。Set通过内部数据结构(如哈希表或红黑树)和算法(如哈希值和equals()方法)实现这一特性,自动过滤重复元素,简化处理逻辑。示例代码展示了Set如何自动忽略重复元素。
178 1
|
存储 算法 Java
Java中的Set,你真的了解它的“无重复”奥秘吗?
在Java的广阔天地里,Set以其独特的“无重复”特性,在众多数据结构中脱颖而出。本文将揭秘Set的“无重复”奥秘,带你领略其魅力。Set通过哈希算法和equals()方法协同工作,确保元素不重复。通过一个简单的案例,我们将展示HashSet如何实现这一特性。
152 1
|
存储 Java 测试技术
滚雪球学Java(56):探究Java中Collection接口,理解集合框架的实现原理
【6月更文挑战第10天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
201 2
滚雪球学Java(56):探究Java中Collection接口,理解集合框架的实现原理
|
存储 Java 索引
从零开始学习 Java:简单易懂的入门指南之Collection集合及list集合(二十一)
从零开始学习 Java:简单易懂的入门指南之Collection集合及list集合(二十一)
【零基础学Java】—Collection集合(三十八)
【零基础学Java】—Collection集合(三十八)