Java

浏览该分类下的所有文章

每日一题(2022/1/20)

代码演示了 Java 中字符串比较的细节。`s1` 通过 `new String("xiaozou")` 在堆中创建了独立对象,`s2` 直接引用常量池中的字面量,两者地址不同,`s1 == s2` 为 `false`。调用 `s1.intern()` 时,若常量池已有相同内容的字符串,则返回该池中对象的引用,否则将其加入池中。因为常量池已经存在 `"xiaozou"`,`s3` 获得的正是 `s2` 的引用,故 `s2 == s3` 为 `true`。文章通过源码解释说明了 `intern()` 的工作原理及其在字符串共享中的作用。

每日一题(2022/1/19)

本文给出一道面试题:在保持 `String s` 引用不变的前提下,使其输出从 `abc` 变为 `abcd`。常规做法如 `StringBuilder.append()` 或 `String.replace()` 均不可行。正确方案是通过反射修改 `String` 的内部 `value`(char[])字段:获取字段、设为可访问、写入新字符数组即可。但在 JDK 11 及以上运行时会抛出 `IllegalArgumentException`,因为 `value` 为 `final` 且受模块系统的非法反射访问限制。文章说明了 `setAccessible(true)` 的作用并解释异常产生的原因。

Dubbo最佳实战

Dubbo是高性能的 Java RPC 框架,官方推荐使用 Zookeeper 作为服务注册中心。文章先概述 Dubbo 的特性与服务治理,随后通过一个基于 Maven 的完整实战案例演示其使用流程:①创建 service‑api 模块定义公共接口;②在 provider 模块引入该接口并实现类,用 @Service 注解将服务注册到 Zookeeper;③在 consumer 模块同样引入接口,通过 @Reference 调用服务。文中提供了所有 Maven 依赖、properties 配置、启动代码以及运行步骤(启动本机 Zookeeper、启动提供者、启动消费者,回车键触发调用),完整源码已上传至 GitHub。

使用HashMap的注意事项

HashMap 的键必须唯一,插入相同键会覆盖旧值。键唯一性的判断先比较 hashCode,再通过 equals 判断真实相等。因此在自定义类作键时必须同时重写 hashCode 与 equals。HashMap 底层结构为数组+链表,JDK 8 之后在链表过长时会转为红黑树;它是非线程安全的,键和值均可为 null,键唯一而值可以重复。本文通过 String 与自定义 Person 类的示例,演示了未重写方法导致键重复的现象,并给出正确实现的代码示例。

Elasticsearch7.x实战指南

Elasticsearch 7.x 通过废弃 TransportClient、统一使用 High‑level REST client、默认类型改为 _doc、分片数降至 1 等改动,提升了连接方式和资源占用。内部升级至 Lucene 8,加入 Weak‑AND、Intervals 查询以及更智能的集群协调与熔断机制,显著优化查询相关性和内存安全。本文系统演示了 ES7 的基本操作(索引、映射、文档的增删改查),以及高级特性包括地理坐标、动态映射、动态模板和 Query DSL 的全文、过滤与聚合用法,为 Java 开发者提供了从集群连接到复杂查询的完整实战指南。

自定义持久层框架(仿MyBatis)

本文介绍了一个仿 MyBatis 的持久层框架实现思路。首先在使用端准备 sqlMapConfig.xml(存放数据源)和 Mapper.xml(定义 SQL 与唯一标识),并建立实体类。框架端通过 Resources 将配置文件读取为流,使用 dom4j 解析后封装到 Configuration(保存 DataSource 与 Map\<statementId, MappedStatement\>)和 MappedStatement(保存 id、resultType、parameterType、sql)中。SqlSessionFactoryBuilder 负责构建 Configuration 并生成 DefaultSqlSessionFactory,openSession() 返回 SqlSession 实例,提供 selectList、selectOne 等 CRUD 方法,内部基于 JDBC 完成数据库操作。整体采用 Builder、Factory、Proxy 等设计模式,并给出完整的 Maven 依赖、数据库建表脚本及代码示例,展示了从配置解析到会话执行的完整流程。

LinkedList常用API详解

本文系统梳理了 Java LinkedList 常用 API 的功能与实现细节,重点包括:peek/peekFirst/peekLast 用于获取头、首、尾元素但不删除;poll/pollFirst/pollLast 用于获取并删除相应元素;offer/offerFirst/offerLast 用于在链表尾部、头部或末尾插入新元素。文中通过示例代码演示了这些方法的调用顺序及运行结果,直观展示了 LinkedList 在元素访问、删除和添加方面的行为,帮助读者快速掌握其常用操作。

集合工具类Collections详解

Collections 是 JDK java.util 包下的集合工具类,提供一系列静态方法,帮助对 List、Collection 等进行排序(reverse、shuffle、sort、swap)、查找(binarySearch、max、min、frequency)、填充(fill)等常用操作。它还能通过 synchronizedXxx 返回线程安全的包装集合,避免 ArrayList、HashMap 的并发问题;提供 empty、singleton、unmodifiable 等创建不可变集合的工厂方法;以及 addAll、disjoint 等实用工具。文章通过代码实例演示了这些方法的使用效果,并指出应深入源码了解实现细节,使用 Collections 能提升编码水平,避免自行实现低效代码。

equals方法该如何重写?

文章说明何时需要重写Object的equals方法,何时可以不写,并详细阐述重写时必须遵守的五条原则(自反、对称、传递、一致、非空),以及常见违规例子。随后以AbstractSet的实现为模板,提供编写高质量equals的步骤:先检查引用相等、类型匹配、大小比较,再用containsAll逐域比较,并配合对应的hashCode实现,强调参数类型必须保持Object。

如何使用Java程序读取zip文档?

本文介绍了在 Java 中使用 `ZipInputStream` 读取 ZIP 文档的基本方法。首先在 Maven 中加入 `commons-io` 依赖,然后通过 `ZipFile` 与 `ZipInputStream`(指定 GBK 编码)打开压缩包,使用 `getNextEntry()` 循环遍历每个 `ZipEntry`,打印路径并对非目录且以 `.txt` 结尾的文件读取内容,利用 `IOUtils.readLines` 将流转为字符串列表。代码示例展示了完整的文件读取、文本输出以及资源的安全关闭,运行后可在控制台打印出压缩包内所有文件及 txt 文件内容。

CGLIB与JDK动态代理

CGLIB和JDK动态代理都是为了解耦而产生的代理技术。JDK代理只能为实现接口的类生成基于接口的代理,需要实现InvocationHandler并使用反射;CGLIB则利用ASM字节码框架为目标类生成子类,覆盖非final方法,可对没有接口的类进行代理。Spring默认:bean实现接口时使用JDK代理,未实现接口时使用CGLIB,亦可强制指定。性能上,JDK在JDK6+及调用次数少时更快,CGLIB在大量调用且JDK8以前可能占优,但对final类/方法无能为力。CGLIB的实现核心是Enhancer.create生成子类并通过MethodInterceptor拦截方法,适用于AOP等场景。

如何避免创建不必要的对象?

在 Java 开发中,应尽量避免创建功能相同的对象以节省内存和提升性能。使用字符串常量池代替 `new String`,在循环中复用同一 `String`;根据需求选用 `String`(不可变)、`StringBuilder`(可变、单线程)或 `StringBuffer`(线程安全)。对布尔值使用 `Boolean.valueOf` 而非 `new Boolean`,因为前者直接返回已缓存的实例。尽量避免自动装箱/拆箱导致的对象创建,优先使用基本类型 `int` 而非包装类 `Integer`。正则表达式应先 `Pattern.compile` 再复用匹配器,避免在循环中重复编译。上述技巧均可显著降低对象创建次数,提升程序运行效率。