加载中

Java

文章分类

浏览该分类下的所有文章

237 篇文章 20

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

在 Java 开发中,应尽量复用已有对象、避免重复创建。使用字面量而非 `new String` 可让字符串进入常量池;根据需求选用不可变的 `String`、可变的 `StringBuilder` 或线程安全的 `StringBuffer`。布尔值应通过 `Boolean.valueOf()` 获取,避免 `new Boolean()` 产生新实例。基本类型优于包装类,避免自动装箱/拆箱带来的额外开销。正则匹配时应先 `Pattern.compile` 并复用 `Pattern`,不要在循环中频繁调用 `String.matches`,可显著提升性能。通过这些细节可减少内存占用并提升运行速度。

如何正确的释放资源?

文章指出在 Java 中手动在 finally 块里关闭 I/O 流会导致代码冗长、易忘记并且异常处理不佳,示例代码演示了这种写法的缺陷。推荐使用 Java 7 引入的 try‑with‑resources,前提是资源实现 AutoCloseable,示例展示了代码的简化与自动释放。文中还提供了一个可变参数的 close 方法作为手动释放的备选,但强调资源释放顺序必须正确。最终结论是:在可行的情况下,优先采用 try‑with‑resources,以获得更简洁、安全的资源管理。

如何实现线程复用?

线程池在执行提交时先尝试创建核心线程,若已满则把任务放入工作队列。添加工作线程通过原子比较并交换安全地增加工作线程计数并创建工作者,工作者内部持有线程并实现可运行任务。线程启动后在工作循环中先执行首次任务,再不断从队列取出任务并调用其运行方法。同一线程在循环中复用,避免重新创建,实现线程复用。线程数受核心线程数、最大线程数和队列容量限制,超出时走拒绝策略。

脏写、脏读、不可重复读和幻读

在并发事务中,未提交的数据可能导致四类并发问题:脏写(两个未提交事务相互覆盖,回滚使后写失效),脏读(事务读到未提交的数据,随后回滚导致读取的值不一致),不可重复读(同一事务多次读取已提交记录,却因其他事务提交而得到不同值),幻读(同一查询条件多次执行,因其他事务插入新记录而出现额外行)。为防止这些问题,数据库提供四种事务隔离级别:READ‑UNCOMMITTED 允许脏读;READ‑COMMITTED 阻止脏读;REPEATABLE‑READ 阻止脏读和不可重复读(MySQL 默认);SERIALIZABLE 最高级别,防止所有三类问题。

isAssignableFrom()方法与instanceof关键字

isAssignableFrom()从类层次判断,调用者为父类Class,参数为子类或自身Class,返回是否“父类可以指派给子类”。instanceof从实例层次判断,左侧为对象实例,右侧为其类或父类,返回对象是否是该类型的实例。二者本质相同但使用场景不同:isAssignableFrom用于反射时的类型比较,instanceof用于运行时对象检测。文章通过接口、父类、子类的代码示例演示了两者的调用方式及相应输出,说明了isAssignableFrom判断父类关系、instanceof判断对象的子类关系。

Spring AOP底层原理

Spring AOP 通过动态代理实现横向切面:当目标对象实现接口时,使用 JDK Proxy 生成代理;若未实现接口,则采用 CGLIB 生成目标类的子类作为代理。代理对象与原实现同级,能够执行相同功能,而无需修改源代码,从而实现 AOP 的横向机制。

JVM之RTTI与反射

RTTI(运行时类型识别)通过获取 Class 对象,在程序运行时获取已知类的完整类型信息,常用 Class.forName、.class 或对象的 getClass() 获得引用。反射则用于处理编译时未知的类,JVM 在运行时加载对应的 .class 文件后,可通过 Class 的 getMethods、getConstructors 等获取成员信息并实例化对象。二者的根本区别在于:RTTI 依赖编译时已知类并在加载时完成检查,而反射在运行时才打开并检查 .class 文件,实现对完全未知类型的动态操作。

getField和getDeclaredField的区别

getField只能获取public字段并包括父类继承的成员;getDeclaredField能获取本类的所有字段(包括private),但不返回继承来的字段,访问私有字段需调用setAccessible(true)。示例演示分别通过这两种方式操作Person类的age和money。反射的优点是运行时动态性强、可配合动态编译实现强大功能;缺点是性能较低、存在安全风险并破坏类的封装性。

常用设计模式

文章介绍了常用的设计模式及其在业务代码中的实际应用。首先通过文件解析的if‑else示例指出违反开闭原则和单一职责原则,引出策略模式的概念——将不同算法封装为实现统一接口的类,并在Spring容器中以Map方式动态获取,实现扩展无需修改原有代码。随后以订单校验为例,说明异常做流程控制的弊端,提出责任链模式:抽象处理器持有下一个节点并实现各自校验逻辑,利用Spring注入和@Order组装链式调用,提升可维护性和解耦性。最后简要提及模板方法模式在统一流程(如商户请求、签名、HTTP调用)中的框架化作用。整体展示了如何通过设计模式优化代码结构、遵循面向对象原则并提升可扩展性。

JVM垃圾收集器ParNew&CMS与底层三色标记算法

文章阐述了JVM的分代垃圾回收策略:新生代使用复制算法,老年代采用标记‑清除或标记‑整理。分别介绍了Serial、Parallel、ParNew 与 CMS 四种收集器的实现原理和适用场景,重点说明 ParNew 可与 CMS 配合实现低停顿的并发回收,并列出 CMS 的关键参数配置。随后深入剖析 CMS 并发标记过程中的三色标记模型、写屏障、浮动垃圾与漏标问题,以及增量更新和 SATB 两种解决方案,帮助读者理解底层实现细节并进行针对性调优。

Class对象的创建方式

本文演示了在 Java 中获取 Class 对象的多种方式。首先通过实例调用 `obj.getClass()`,得到运行时对象的类;其次使用 `Class.forName("full.package.Name")` 按类全路径加载;再次直接使用类字面量 `ClassName.class`;对基本类型,可通过其包装类的 `TYPE` 字段获取对应的 Class(如 `Integer.TYPE` 表示 `int`);最后可通过已有 Class 的 `getSuperclass()` 方法取得父类的 Class。文章配以完整代码和运行结果,说明各方法返回的 Class 对象在哈希码上相同,验证了获取方式的等价性。

JVM垃圾收集器汇总

Serial:单线程、停顿大,适用于Client模式小堆;ParNew:Serial的多线程版,配合CMS使用;Parallel Scavenge:多线程复制收集,侧重吞吐量,可调‑XX:MaxGCPauseMills/‑XX:GCTimeRatio;Serial Old:单线程标记‑整理,Client或CMS备选;Parallel Old:Parallel Scavenge对应的老年代,多线程标记‑整理,提升服务器吞吐;CMS:并发标记‑清除,目标最短停顿,但占用CPU、产生碎片;G1:面向大堆的分代收集器,支持暂停时间可预测,调参简洁(‑XX:+UseG1GC、‑XX:MaxGCPauseMillis)。