加载中

面试

文章分类

浏览该分类下的所有文章

29 篇文章 3

浅谈分布式唯一ID生成方案

分布式唯一ID必须全局唯一、有序、可用、自主且安全。常见方案包括UUID(本地生成、长度长、可能泄露信息)、数据库自增(实现简单但依赖DB)、Redis INCR、Zookeeper节点版本以及Snowflake算法(64位结构、支持高并发但受时钟回拨影响)。为降低DB压力,业界采用号段模式,如美团Leaf‑segment、滴滴Tinyid、微信序列号,通过批量号段缓存实现高效、容错。Snowflake的变种有Leaf‑snowflake、百度UidGenerator、基于多时间线的改进,分别通过工作机器ID分配、RingBuffer预生成或多时间线来解决时钟回拨和吞吐瓶颈。全文评估了各方案的优缺点并给出实践选型思路。

es 在数据量很大的情况下(数十亿级别)如何提高查询效率?

es 在大规模数据(十亿级)下的查询性能主要依赖 OS 缓存;因此应让索引文件尽量能放入内存。可通过减少写入字段、将非检索数据迁至 MySQL/HBase、对热点数据预热、冷热分离(热、冷数据分别建索引并分配节点)来降低磁盘访问。文档模型要在写入时完成关联,避免在 ES 中使用 join、nested、parent‑child 等高开销操作。分页应避免深度分页,改用 scroll 或 search_after 逐页获取快照。上述措施综合使用,可显著提升 ES 在海量数据下的查询效率。

如何对Integer和Double类型判断相等?

Integer 与 Double 不能直接用 `==`、字符串或 `compareTo` 比较,因为它们是不同的包装类型且 `compareTo` 只能同类比较。两者均继承自 `Number`,可以通过 `doubleValue()`(或其他数值转换方法)将它们转换为相同的基本类型后再使用 `==` 判断相等。例如:`Integer i = 100; Double d = 100.00; System.out.println(i.doubleValue() == d.doubleValue());` 这样即可正确比较整数与浮点数的数值是否相等。

反射的基本概念

反射是一种在运行时动态获取、创建、检查和调用类及其成员(包括 private)的机制,核心类为 Class、Constructor、Method、Field。它可用于突破访问限制、实现自定义注解、动态加载第三方 jar、按需加载以缩短编译和初始化时间。实现原理是 ClassLoader 将 .class 文件加载后生成 Class 对象,反射通过上述四个类操作这些对象。优点是灵活自由,缺点包括性能下降、破坏封装导致安全风险以及 API 变动时的兼容性问题。适度、按需使用可将影响降至可接受范围。

如何让 a == 1 && a == 2 && a == 3同时成立?

文章介绍了利用 Java Integer 缓存实现 `a==1 && a==2 && a==3` 同时成立的技巧。先说明 JDK 为 -128~127 的 Integer 实例化提供了内部类 IntegerCache,范围内的对象会被复用。通过反射获取该缓存数组,将索引对应 2、3 的元素指向存放 1 的对象,随后 `Integer a = 1;` 的自动装箱会从缓存取值,导致 `a` 与 `(Integer)1、2、3`、`Integer.valueOf(1..3)` 均引用同一实例,比较为 true;而 `new Integer(...)` 每次都会创建新对象,地址不同,比较为 false。文章以源码分析解释了缓存机制和 `valueOf` 与构造函数的区别,并指出此类 JDK 特性在面试和性能优化中的价值。

for(;;)和while(true)的区别

文章说明 Java 中的两种死循环写法 `for(;;)` 与 `while(true)` 在功能上完全等价。通过对比 JDK 源码示例和编译后生成的字节码,发现两者的字节码已完全相同,现代编译器会进行等价优化。之所以很多作者仍倾向使用 `for(;;)`,是源于早期 C 语言和早期 Java 编译器中 `for(;;)` 生成的指令更少、占用更少内存的历史习惯。如今两者在性能和行为上没有差别,仅是编码风格的选择。

this与super关键字详解

本文系统阐述了 Java 中 `this` 与 `super` 两个关键字的概念、作用及使用规则。`this` 代表当前对象实例,可用于访问本类属性、调用本类方法、在构造器首行调用本类的其他构造函数以及区分成员变量与形参。`super` 则指向直接父类的实例引用,用于访问父类的非私有属性和方法、在子类覆盖后仍能调用父类同名成员,以及在构造器首行显式调用父类构造函数。文章通过父类/子类示例演示了隐式 `super()` 导致的编译错误及两种解决方案:在父类提供无参构造函数或在子类显式 `super(…)` 调用有参构造函数,并对两者的查找范围、功能差异进行对比总结,帮助读者正确、规范地使用这两个关键字。

还在频繁定义常量?不如试试用枚举代替

文章指出在需要一组在编译时已确定的固定值时,频繁使用字符串常量并不理想,建议改用枚举。枚举提供类型安全、可定义属性和方法、支持遍历及关联业务逻辑(如 HttpStatus 示例),使代码更简洁、可维护且功能更强。但并非所有常量都必须转为枚举,仍需根据具体场景权衡选择。

面试官:synchronized可以锁字符串吗?

synchronized只能对同一对象加锁,若锁的是字符串,必须保证锁对象的引用相同。`new String("常量")`每次都会创建新对象,地址不同,无法实现互斥;而直接使用常量或调用 `intern()` 将字符串放入字符串常量池后,所有线程会获取同一引用,才能真正加锁。由于把大量字符串放入常量池会导致内存占用和Full GC 问题,实践中更推荐使用 Guava 的 `Interner`(弱引用实现)来管理锁对象,既保证唯一性,又能在内存紧张时自动回收。

Explain详解与索引最佳实践

EXPLAIN 用 EXPLAIN 关键字模拟优化器执行,返回查询计划而非结果。支持 EXPLAIN EXTENDED(显示优化信息并可通过 SHOW WARNINGS 查看改写语句)和 EXPLAIN PARTITIONS(显示访问的分区)。文章详细解释了每列含义:id、select_type、table、type(访问方式从 system、const、eq_ref、ref、range、index 到 ALL)、possible_keys、key、key_len、ref、rows、Extra(如 Using index、Using where、Using temporary、Using filesort 等)。通过示例表展示索引的使用情况及 key_len 计算规则。索引最佳实践包括:复合索引遵守最左前缀原则,避免在索引列上使用函数或隐式类型转换导致失效;范围查询应使用合适的索引;利用覆盖索引可显著提升查询效率。

面试篇【三】

文章讨论Java面试常见知识点,包括GC根对象及不可达对象的回收机制、字符编码体系与UTF‑8中文字节数、静态代理与动态代理的区别、异常体系及Checked/Unchecked划分、方法解析与分派(静态/动态)、equals/hashCode的使用规则、实现多态的必要条件、对象序列化方式、反射的原理与用法、注解的定义与元注解、泛型的擦除实现、String不可变的原因与内部实现、Redis六大数据结构及适用场景、缓存穿透/击穿/雪崩的防护方案,以及Kafka、RabbitMQ、RocketMQ在性能、可靠性和可用性方面的对比。

深入理解Mysql索引底层数据结构与算法

索引是 MySQL 用于快速定位数据的有序结构,常见实现包括二叉树、红黑树、Hash、B‑Tree 与 B+Tree。InnoDB 采用聚集索引,数据本身以 B+Tree 组织,叶节点存完整记录;主键建议使用整数自增,以保证唯一、占用小、插入稳定。非主键(辅助)索引只保存索引键和主键值,查询时需先定位辅助索引再“回表”到主键树获取完整行。联合索引遵循左前缀原则,省去冗余单列索引。MyISAM 则使用非聚集索引,索引文件与数据文件分离。相较于 B‑Tree,B+Tree 只在叶子存数据且叶子链式相连,提升了范围查询和磁盘 I/O 效率,是 MySQL 默认的底层索引结构。