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

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

目录
相关文章
|
6天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
33 17
|
1天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
19 4
|
4天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
19 4
|
2天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
9 2
|
7天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
27天前
|
存储 JavaScript 前端开发
Set、Map、WeakSet 和 WeakMap 的区别
在 JavaScript 中,Set 和 Map 用于存储唯一值和键值对,支持多种操作方法,如添加、删除和检查元素。WeakSet 和 WeakMap 则存储弱引用的对象,有助于防止内存泄漏,适合特定场景使用。
|
2月前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
34 6
【数据结构】map&set详解
|
29天前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
31 1
|
2月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
35 5
|
2月前
|
存储 JavaScript 前端开发
js的map和set |21
js的map和set |21