加载中

Java

文章分类

浏览该分类下的所有文章

237 篇文章 20

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

在Java 开发中,应尽量复用对象以降低内存占用和提升性能。利用常量池避免在循环中创建重复的 `String`,推荐使用字面量而非 `new String()`;`String` 适用于不可变文本,`StringBuilder` 与 `StringBuffer` 用于可变拼接,后者提供同步。`Boolean` 也应通过 `Boolean.valueOf()` 获取常量,避免 `new Boolean()` 的额外实例。基本类型优先使用原始类型而非包装类,以减少自动装箱/拆箱带来的开销。正则匹配时,避免在循环内调用 `String.matches()`(会每次编译),应预编译 `Pattern` 并复用,以显著提升执行效率。

如何正确的释放资源?

文章指出手动在 finally 中关闭 I/O 流代码冗长且易漏,推荐使用 Java 7 的 try‑with‑resources,它要求资源实现 AutoCloseable,能够自动安全地释放资源,代码更简洁、可读性更高。文中还提供了一个接受可变 Closeable 参数的统一关闭方法,强调释放顺序的重要性,但最终结论是:在可用时仍应首选 try‑with‑resources 以实现优雅的资源管理。

如何实现线程复用?

文章通过分析 `ThreadPoolExecutor` 的 `execute`、`addWorker` 与内部 `Worker` 类源码,阐明线程池如何实现线程复用。核心在于:当线程数未达核心阈值时创建新 Worker;否则任务被放入队列,已有 Worker 在 `runWorker` 循环中不断调用 `task.run()` 执行新任务。`Worker` 本身实现 `Runnable`,其 `run` 方法仅调用 `runWorker`,而 `runWorker` 通过 `while(task!=null || (task=getTask())!=null)` 循环获取并执行任务,不会为每个任务重新创建线程,从而实现同一线程的重复利用,提升性能并避免频繁的创建/销毁开销。

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

本文阐述了并发事务下的四种典型异常:脏写(未提交事务被后续事务覆盖后回滚导致数据丢失),脏读(事务读取了未提交且可能回滚的数据),不可重复读(同一事务中多次查询已提交的记录却得到不同值),以及幻读(同一查询条件在事务期间因其他事务插入新行而返回额外记录)。这些问题源于事务并发冲突,数据库通过事务隔离级别(READ‑UNCOMMITTED、READ‑COMMITTED、REPEATABLE‑READ、SERIALIZABLE)及锁、MVCC 等机制加以防护,其中 MySQL 默认采用 REPEATABLE‑READ。

isAssignableFrom()方法与instanceof关键字

isAssignableFrom()是基于类对象的继承关系判断,调用者必须是父类Class,参数为自身或子类Class;返回 true 表示参数类是调用者的子类或相同类。instanceof 则在运行时对具体对象进行判断,左侧是实例,右侧是该实例的类或父类,返回 true 表示该对象是右侧类型的实例(即右侧是左侧对象的父类或本身)。二者的判断方向相反:isAssignableFrom 判断“父类←子类”,instanceof 判断“子类→父类”。文章通过接口、父类、子类的代码示例,分别演示了两者的调用方式及结果,说明了它们在语义和使用场景上的区别。

Spring AOP底层原理

Spring AOP 通过动态代理实现横向切面。若目标对象实现了接口,Spring 使用 JDK 动态代理(Proxy)生成代理类;若目标对象未实现接口,则采用 CGLIB 为其生成子类作为代理。代理对象与原实现类功能相同,但本质上是一个代理层,能够在不修改源码的前提下插入横向逻辑,实现 AOP 功能。

JVM之RTTI与反射

RTTI(运行时类型识别)通过获取类对应的 Class 对象,在程序运行时获知对象的完整类型信息,包括父类、接口、方法和成员。获取 Class 的方式有 Class.forName、类字面量 .class 以及对象的 getClass(),前两者会触发类加载器加载并(或延迟)初始化类。RTTI 的前提是编译时已知目标类名。反射则突破此限制,能够在运行时根据字符串加载未知类的 .class 文件,随后通过 Class 的 getMethods、getConstructors 等接口获取 Method、Constructor 对象并实例化对象。根本区别在于:RTTI 在编译期已知类并检查 .class 文件,反射则在运行时才获取并检查 .class 文件,以实现对完全未知类型的动态操作。

getField和getDeclaredField的区别

getField只能获取public字段,且会查找父类继承的成员;getDeclaredField则返回本类声明的所有字段(包括private),但不包括继承来的。示例中通过getDeclaredField获取Person的private age并使用setAccessible(true)读取和修改值,通过getField获取public money直接操作。运行结果显示私有字段需先打开访问权限,公共字段可直接访问。文章最后指出反射的优势在于运行时动态获取类信息、提升灵活性和可与动态编译结合使用;缺点是性能较低、安全性差并破坏封装。

常用设计模式

文章以代码优化为切入,介绍常用设计模式的概念与实践。通过示例说明 if‑else 分支导致的开闭原则和单一职责违背,提出策略模式,将不同解析算法封装为实现同一接口的类并在 Spring 中映射;随后指出异常做流程控制的弊端,演示责任链模式如何把校验、安检等步骤串成链式处理;最后简要提及模板方法模式在统一业务流程(如商户请求、签名、http 调用)中的抽象骨架。

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

本文介绍了JVM的分代垃圾回收模型及常用收集器,重点阐述了适用于Server模式的ParNew 与 CMS 组合的工作原理。ParNew 在新生代采用复制算法,CMS 在老年代实现并发标记‑清除,通过初始标记、并发标记、重新标记和并发清理四阶段实现最短停顿。文中进一步解释了 CMS 底层的三色标记、写屏障以及浮动垃圾、漏标问题,并提供了在高并发电商系统中使用‑Xmn、‑XX:MaxTenuringThreshold、‑XX:PretenureSizeThreshold 等参数调优的实践方案。

Class对象的创建方式

文章演示了在 Java 中获取 Class 对象的多种方式。首先通过实例调用 obj.getClass() 获得运行时类;其次使用 Class.forName("全路径") 通过类名字符串加载;再次直接使用类字面量 ClassName.class 获取;对于基本类型,可通过包装类的 TYPE 常量得到对应的 Class;最后可通过已有 Class 的 getSuperclass() 方法获取父类的 Class。示例代码展示了每种方法的实现及输出结果,帮助理解反射机制中 Class 对象的创建途径。

JVM垃圾收集器汇总

Serial 收集器是单线程、停顿式的最早新生代/老年代收集器,适合 Client 模式小堆;ParNew 为其多线程版,可配合 CMS 使用,适合 Server 环境;Parallel Scavenge(新生代)和 Parallel Old(老年代)采用并行复制/标记‑整理,侧重提升吞吐量;CMS 采用并发标记‑清除,目标最短停顿,但对 CPU 敏感且产生碎片;G1 采用分区、可预测停顿的混合回收策略,提供简单可调的性能。不同收集器在停顿时间、吞吐量和资源利用上各有侧重,依据堆大小、CPU 核数和业务交互需求选择合适组合。