Java Set实现类面试题

news/2025/2/25 17:15:00

Java Set实现类面试题

HashSet

Q1: HashSet的实现原理是什么?

HashSet是基于HashMap实现的,使用HashMap的key来存储元素,value统一使用一个Object对象。

java">public class HashSetPrincipleExample {
    // 模拟HashSet的基本实现
    public class SimpleHashSet<E> {
        private static final Object PRESENT = new Object();
        private HashMap<E, Object> map;
        
        public SimpleHashSet() {
            map = new HashMap<>();
        }
        
        public boolean add(E e) {
            return map.put(e, PRESENT) == null;
        }
        
        public boolean remove(Object o) {
            return map.remove(o) == PRESENT;
        }
        
        public boolean contains(Object o) {
            return map.containsKey(o);
        }
        
        public int size() {
            return map.size();
        }
    }
}

Q2: HashSet如何保证元素不重复?

java">public class HashSetDuplicationExample {
    public static class Person {
        private String name;
        private int age;
        
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        // 错误的hashCode实现
        public int badHashCode() {
            return 1; // 所有对象都返回相同的hash值
        }
        
        // 正确的hashCode实现
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
        
        // 正确的equals实现
        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof Person)) return false;
            Person other = (Person) obj;
            return age == other.age && 
                   Objects.equals(name, other.name);
        }
    }
    
    public void demonstrateDuplication() {
        Set<Person> set = new HashSet<>();
        set.add(new Person("Tom", 20));
        set.add(new Person("Tom", 20)); // 不会被添加,因为equals返回true
        System.out.println("Set size: " + set.size()); // 输出1
    }
}

TreeSet

Q3: TreeSet的实现原理是什么?

TreeSet是基于TreeMap实现的,它是一个有序集合。

java">public class TreeSetPrincipleExample {
    // 1. 使用自然排序
    public void naturalOrdering() {
        TreeSet<String> set = new TreeSet<>();
        set.add("C");
        set.add("A");
        set.add("B");
        System.out.println(set); // 输出 [A, B, C]
    }
    
    // 2. 使用自定义排序
    public void customOrdering() {
        TreeSet<Person> set = new TreeSet<>((p1, p2) -> {
            int ageCompare = Integer.compare(p1.getAge(), p2.getAge());
            if (ageCompare != 0) return ageCompare;
            return p1.getName().compareTo(p2.getName());
        });
        
        set.add(new Person("Tom", 20));
        set.add(new Person("Jerry", 18));
        set.add(new Person("Bob", 20));
    }
    
    // 3. 实现Comparable接口
    public static class ComparablePerson implements Comparable<ComparablePerson> {
        private String name;
        private int age;
        
        @Override
        public int compareTo(ComparablePerson other) {
            int ageCompare = Integer.compare(this.age, other.age);
            if (ageCompare != 0) return ageCompare;
            return this.name.compareTo(other.name);
        }
    }
}

LinkedHashSet

Q4: LinkedHashSet的特点是什么?

LinkedHashSet是HashSet的子类,它使用LinkedHashMap来存储元素,维护了元素的插入顺序。

java">public class LinkedHashSetExample {
    public void demonstrateOrdering() {
        // 1. HashSet不保证顺序
        Set<String> hashSet = new HashSet<>();
        hashSet.add("C");
        hashSet.add("A");
        hashSet.add("B");
        System.out.println("HashSet: " + hashSet); // 顺序不确定
        
        // 2. LinkedHashSet保持插入顺序
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("C");
        linkedHashSet.add("A");
        linkedHashSet.add("B");
        System.out.println("LinkedHashSet: " + linkedHashSet); // 输出 [C, A, B]
        
        // 3. TreeSet按照自然顺序
        Set<String> treeSet = new TreeSet<>();
        treeSet.add("C");
        treeSet.add("A");
        treeSet.add("B");
        System.out.println("TreeSet: " + treeSet); // 输出 [A, B, C]
    }
}

性能比较

Q5: 不同Set实现类的性能对比?

java">public class SetPerformanceComparison {
    public void comparePerformance() {
        int n = 100000;
        
        // 1. 添加性能
        long start = System.currentTimeMillis();
        Set<Integer> hashSet = new HashSet<>();
        for (int i = 0; i < n; i++) {
            hashSet.add(i);
        }
        System.out.println("HashSet添加耗时:" + (System.currentTimeMillis() - start));
        
        start = System.currentTimeMillis();
        Set<Integer> treeSet = new TreeSet<>();
        for (int i = 0; i < n; i++) {
            treeSet.add(i);
        }
        System.out.println("TreeSet添加耗时:" + (System.currentTimeMillis() - start));
        
        start = System.currentTimeMillis();
        Set<Integer> linkedHashSet = new LinkedHashSet<>();
        for (int i = 0; i < n; i++) {
            linkedHashSet.add(i);
        }
        System.out.println("LinkedHashSet添加耗时:" + (System.currentTimeMillis() - start));
        
        // 2. 查找性能
        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            hashSet.contains(i);
        }
        System.out.println("HashSet查找耗时:" + (System.currentTimeMillis() - start));
        
        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            treeSet.contains(i);
        }
        System.out.println("TreeSet查找耗时:" + (System.currentTimeMillis() - start));
    }
}

Q6: 如何选择合适的Set实现类?

java">public class SetSelectionExample {
    public void demonstrateUsage() {
        // 1. 需要最高性能,不关心顺序
        Set<String> hashSet = new HashSet<>();
        
        // 2. 需要排序
        Set<String> treeSet = new TreeSet<>();
        
        // 3. 需要记住插入顺序
        Set<String> linkedHashSet = new LinkedHashSet<>();
        
        // 4. 自定义排序示例
        Set<Person> customSortedSet = new TreeSet<>((p1, p2) -> {
            // 按年龄排序,年龄相同按姓名排序
            int ageCompare = Integer.compare(p1.getAge(), p2.getAge());
            if (ageCompare != 0) return ageCompare;
            return p1.getName().compareTo(p2.getName());
        });
        
        // 5. 需要线程安全
        Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
        
        // 6. 并发环境下的有序Set
        Set<String> concurrentSkipListSet = new ConcurrentSkipListSet<>();
    }
    
    // 使用场景示例
    public void usageScenarios() {
        // 1. 去重场景
        Set<String> uniqueEmails = new HashSet<>();
        uniqueEmails.add("user@example.com");
        uniqueEmails.add("user@example.com"); // 重复邮箱不会被添加
        
        // 2. 排序场景
        Set<Integer> sortedNumbers = new TreeSet<>();
        sortedNumbers.add(3);
        sortedNumbers.add(1);
        sortedNumbers.add(2);
        // 遍历时自动排序
        
        // 3. 记录访问顺序场景
        Set<String> pageViews = new LinkedHashSet<>();
        pageViews.add("/home");
        pageViews.add("/products");
        pageViews.add("/about");
        // 保持用户访问页面的顺序
    }
}

面试关键点

  1. 理解不同Set实现类的底层原理
  2. 掌握HashSet的去重机制
  3. 了解TreeSet的排序原理
  4. 熟悉LinkedHashSet的特点
  5. 掌握Set的选择原则
  6. 注意性能和线程安全
  7. 理解equals和hashCode的重要性
  8. 掌握自定义排序的实现方式

http://www.niftyadmin.cn/n/5865753.html

相关文章

bitcoinjs学习笔记2-P2SH

BitcoinJS 学习笔记 2 - P2SH 1.概述 1.1 P2SH 是什么&#xff1f; 1.1.1 定义&#xff1a;Pay to Script Hash P2SH 允许你将比特币发送到一个“脚本的哈希值”上&#xff0c;而不是像P2PKH直接发送到一个“公钥的哈希值”上即P2SH的地址的脚本的哈希值&#xff0c;而P2PKH的…

服务器能否拒绝非浏览器发起的HTTP请求?

互联网各领域资料分享专区(不定期更新): Sheet 前言 服务器可以采取多种方法来拒绝非浏览器发起的HTTP请求,但需要明确的是:HTTP协议本身并不限制客户端类型,任何符合协议规范的请求都会被处理。因此,拒绝非浏览器请求需依赖额外策略。 正文 一、基于请求头过滤 1、Us…

【备赛】点亮LED

LED部分的原理图 led前面有锁存器&#xff0c;这是为了防止led会受到lcd的干扰&#xff08;lcd也需要用到这些引脚&#xff09;。 每次想要对led操作&#xff0c;就需要先打开锁存器&#xff0c;再执行操作&#xff0c;最后关闭锁存器。 这里需要注意的是&#xff0c;引脚配置…

mysql 学习17 SQL 锁

概述 全局锁 通过全局锁 进行数据备份 表级锁 表锁 元数据锁 意向锁 原先 A线程 开启了一个事务&#xff0c;udpate id 3的数据&#xff0c;就会有一个行级锁&#xff0c;锁定第三行 这时候如果B线程要 lock tables 这个表 read&#xff0c;那么理论上就要锁定这一行表。 那…

8.spring对logback的支持

文章目录 一、入口二、源码解析LoggingApplicationListener 三、其它支持四、总结 本节以logback为背景介绍的 一、入口 gav: org.springframework.boot:spring-boot:3.3.4 spring.factories文件中有如下两个配置 org.springframework.boot.logging.LoggingSystemFactory\ …

【Java 8】Lambda表达式介绍

目录 1、Lambda简介 2、语法介绍 3、Lambda表达式示例 3.1、无参数的 Lambda 表达式 3.2、单个参数的 Lambda 表达式 3.3、多个参数的 Lambda 表达式 3.4、带语句块的 Lambda 表达式 4、Lambda使用场景 4.1、替代匿名内部类 4.2、集合操作 4.3、排序 4.4、函数式接口…

Java使用EasyExcel实现异步导出

以下是使用 EasyExcel 工具类实现异步导出功能的 Demo&#xff0c;包括用户发起导出请求后&#xff0c;系统先返回响应&#xff0c;后台读取数据并上传至 COS&#xff0c;最后通知用户下载的完整流程。 实现步骤 用户发起导出请求 前端调用导出接口&#xff0c;后端立即返回响应…

【Linux】Ubuntu中,如何创建软件的快捷方式放到桌面上

本文主要介绍Ubuntu中&#xff0c;如何创建软件的快捷方式放到桌面上 首先进入到/usr/share/applications/路径下&#xff0c;找到自己想要的软件&#xff0c;这里以我的vim为例子 ricardoDESKTOP-8T8LHV5:/usr/share/applications$ ls byobu.desktop io.snapcraft.SessionA…