当前位置:首页 > 随笔 > 正文内容

Java核心技术精要:从基础到分布式系统

访客 随笔 2026年8月30日 1

Java基础核心概念

JDK与JRE的区别
JDK(Java Development Kit)是完整的开发环境,包含编译器(javac)、调试工具、文档生成器及JRE。JRE(Java Runtime Environment)仅提供运行Java程序所需的虚拟机和核心类库。若仅需执行程序,安装JRE即可;开发则必须使用JDK。

== 与 equals 的本质差异
== 对基本类型比较数值,对引用类型比较内存地址。而 equals() 默认行为与 == 相同,但多数包装类(如String、Integer)重写了该方法以实现值比较。例如:

String a = "hello";
String b = new String("hello");
System.out.println(a == b);        // false(不同对象)
System.out.println(a.equals(b));   // true(内容相同)

hashCode() 与 equals() 的关系
两个对象的 hashCode 相同,不代表 equals 为 true。哈希碰撞是正常现象。例如:

String s1 = "通话";
String s2 = "重地";
System.out.println(s1.hashCode() == s2.hashCode()); // true
System.out.println(s1.equals(s2));                  // false

这是由于哈希算法的特性,不同字符串可能映射到相同哈希值。

final 关键字的三种用途
- 修饰类:禁止继承
- 修饰方法:禁止子类重写
- 修饰变量:成为常量,初始化后不可更改

Math.round(-1.5) 的结果
返回 -1。Java 中 round() 的规则是"四舍五入到最接近整数,0.5 向正无穷方向取整",因此 -1.5 向 -1 舍入。

String 是否为基础类型
不是。Java 基础类型共8种:byte, short, int, long, float, double, boolean, char。String 是 java.lang.String 类的实例,属于引用类型。

String、StringBuilder、StringBuffer 的区别
- String:不可变,每次修改生成新对象
- StringBuilder:可变,非线程安全,性能高
- StringBuffer:可变,线程安全,性能较低
在单线程环境下推荐使用 StringBuilder,多线程场景使用 StringBuffer。

字符串反转实现
使用 StringBuilder 或 StringBuffer 的 reverse() 方法:

String reversed = new StringBuilder("abcdefg").reverse().toString();

抽象类与接口
- 抽象类可包含构造器、成员变量、非抽象方法;接口只能有 public static final 常量和 public abstract 方法(Java 8 后可有 default 和 static 方法)
- 类只能继承一个抽象类,但可实现多个接口
- 抽象类用于"is-a"关系,接口用于"can-do"能力定义

集合框架深度解析

HashMap 底层原理
JDK 8 之后,HashMap 采用数组 + 链表 + 红黑树结构。当链表长度 ≥ 8 且数组容量 ≥ 64 时,链表转换为红黑树以提升查询效率。键的哈希值通过 hash(key.hashCode()) 运算后与数组长度减一进行位运算,确定存储位置。冲突时使用链表或红黑树解决。

HashSet 实现机制
HashSet 内部使用 HashMap 实现,所有元素作为键存储,值统一为一个静态对象 PRESENT。其唯一性由 HashMap 的键唯一性保证。

ArrayList 与 LinkedList 性能对比
- 随机访问:ArrayList O(1),LinkedList O(n)
- 插入/删除(非首尾):ArrayList O(n),LinkedList O(1)
- 内存占用:LinkedList 每节点额外存储前后指针,开销更大
高频读取选 ArrayList,高频增删选 LinkedList。

线程安全集合
- 传统:Vector、Hashtable
- 并发包:ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue
推荐使用 java.util.concurrent 包中的并发集合,性能优于同步包装类。

不可变集合创建
使用 Collections.unmodifiableList/set/map() 创建只读视图,任何修改操作抛出 UnsupportedOperationException。

多线程与并发控制

线程状态生命周期
NEW → RUNNABLE → BLOCKED → WAITING/TIMED_WAITING → TERMINATED
- BLOCKED:等待获取锁
- WAITING:调用 wait()/join()/park() 无限等待
- TIMED_WAITING:调用 sleep()/wait(timeout)/parkNanos() 等待指定时间

sleep() 与 wait() 的核心差异
| 特性 | sleep() | wait() | |------|---------|--------| | 来源类 | Thread | Object | | 是否释放锁 | 否 | 是 | | 唤醒方式 | 时间到自动唤醒 | 需 notify()/notifyAll() | | 使用场景 | 简单延时 | 线程协作、生产者消费者 |

线程池创建方式
推荐使用 ThreadPoolExecutor 手动配置,避免使用 Executors 提供的快捷方法(如 newFixedThreadPool),因其使用无界队列易导致 OOM。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    4, 8, 60L, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100),
    new ThreadPoolExecutor.CallerRunsPolicy()
);

synchronized 锁升级机制
Java 6+ 引入锁优化:偏向锁 → 轻量级锁 → 重量级锁
- 偏向锁:无竞争时,锁直接绑定线程,避免CAS
- 轻量级锁:竞争出现时,使用CAS替换对象头指针,自旋等待
- 重量级锁:自旋失败后,线程挂起进入阻塞队列
该机制大幅降低无竞争场景下的同步开销。

volatile 与 synchronized 对比
- volatile:保证可见性与有序性,不保证原子性
- synchronized:保证原子性、可见性、有序性,但会阻塞线程
适用于状态标记(如 shutdownFlag)用 volatile,复合操作(如 i++)必须用 synchronized 或 Lock。

ThreadLocal 使用场景
为每个线程提供独立变量副本,典型用途:数据库连接、事务上下文、用户会话信息。注意:使用后需手动 remove() 避免内存泄漏。

网络与Web开发

HTTP 301 与 302 区别
- 301:永久重定向,搜索引擎更新索引
- 302:临时重定向,搜索引擎保留原URL
SEO优化推荐使用301。

Forward 与 Redirect
| 特性 | Forward | Redirect | |------|---------|----------| | 地址栏变化 | 否 | 是 | | 数据共享 | 可共享 request | 不可共享 | | 请求次数 | 1次 | 2次 | | 性能 | 更高 | 较低 |

跨域解决方案
- CORS:服务端设置响应头 Access-Control-Allow-Origin
- JSONP:仅支持GET,通过动态script标签实现(已逐步淘汰)
- 代理服务器:Nginx反向代理统一域名

数据库与ORM

MySQL索引优化原则
- 遵循最左前缀原则
- 避免在索引列上使用函数或表达式
- 联合索引中,区分度高的字段放左侧
- 尽量使用覆盖索引(查询字段全在索引中)

InnoDB 与 MyISAM 对比
| 特性 | InnoDB | MyISAM | |------|--------|--------| | 事务支持 | 支持 | 不支持 | | 锁粒度 | 行锁 | 表锁 | | 外键 | 支持 | 不支持 | | COUNT(*)性能 | 需全表扫描 | 快(保存行数) | | 适用场景 | 高并发写入 | 读多写少 |

事务隔离级别
- READ UNCOMMITTED:脏读允许
- READ COMMITTED:避免脏读,允许可重复读
- REPEATABLE READ(MySQL默认):避免脏读和不可重复读,允许多幻读
- SERIALIZABLE:完全串行化,性能最低

Redis核心机制

缓存穿透解决方案
对查询不存在的数据,缓存一个空值(如 null)并设置短过期时间(如5分钟),防止恶意请求持续穿透。

缓存击穿解决方案
对热点数据使用互斥锁(Redis SETNX)或逻辑过期策略:设置一个稍长的过期时间,但缓存中额外保存一个"逻辑过期时间",当请求发现逻辑过期时,由一个线程异步刷新数据,其他线程仍返回旧值。

Redis持久化策略
- RDB:定时快照,恢复快,数据可能丢失
- AOF:记录写操作日志,数据更安全,文件大,恢复慢
推荐开启 AOF + RDB 双重机制。

Redis淘汰策略
- volatile-lru:过期键中选最近最少用
- allkeys-lru:所有键中选最近最少用(推荐)
- volatile-ttl:优先淘汰剩余时间最短的
- noeviction:拒绝写入(默认)

JVM内存与调优

堆内存结构
- 新生代:Eden : S0 : S1 = 8:1:1
- 老年代:存放长期存活对象
- 元空间(Metaspace):存放类元数据,使用本地内存

垃圾回收算法
- 标记-清除:产生碎片
- 标记-整理:消除碎片,但移动成本高
- 复制算法:适用于新生代,效率高但浪费一半空间
- 分代收集:主流策略,新生代用复制,老年代用标记-整理

常用JVM参数
- -Xms4g -Xmx4g:堆初始与最大大小一致,避免动态扩容
- -XX:NewRatio=3:老年代/新生代比例为3:1
- -XX:SurvivorRatio=8:Eden:S0:S1 = 8:1:1
- -XX:+UseG1GC:JDK9+默认GC,适合大堆低延迟场景
- -XX:+PrintGCDetails:输出详细GC日志

设计模式与框架

Spring Bean作用域
- singleton(默认):容器中唯一实例
- prototype:每次请求创建新实例
- request/session:Web环境下绑定请求或会话
- application:ServletContext级别共享
- websocket:WebSocket会话级别

AOP实现原理
基于动态代理:JDK代理(接口)或 CGLIB(继承类)。Spring通过切点表达式匹配目标方法,在执行前后织入通知逻辑,实现横切关注点(日志、事务、权限)的解耦。

MyBatis #{} 与 ${} 区别
- #{} :预编译参数,自动转义,防SQL注入
- ${} :字符串替换,直接拼接,易受注入攻击
推荐所有参数使用 #{} ,动态表名/列名等特殊情况谨慎使用 ${}

ZooKeeper在分布式系统中的作用
- 服务注册与发现(如Dubbo)
- 配置中心(动态推送)
- 分布式锁(临时顺序节点)
- Leader选举(ZAB协议)

并发工具类

CountDownLatch 与 CyclicBarrier
- CountDownLatch:倒计时器,一次性使用,等待N个线程完成
- CyclicBarrier:栅栏,可重用,等待N个线程到达后同时继续

CompletableFuture 异步编程
支持链式调用、组合、异常处理:

CompletableFuture.supplyAsync(() -> fetchData())
    .thenApply(data -> transform(data))
    .exceptionally(ex -> handle(ex))
    .thenAccept(result -> System.out.println(result));

相关文章

可以按小时收费的VPS

很多 VPS 提供商都支持 按小时计费(hourly billing),想短期试用 / 临时搭建节点、测试网络、短期项目等场景非常合适。下面是当前最主流且靠谱的按小时 VPS 选项,分别按不同需求场景整理: 1. Vultr(全球节点,包括日本) 按小时计费 可选机房:东京 / 大阪 / 洛杉矶 / 法兰克福 / 伦敦 … 支持 PayPal(部分情况),但更常用信用卡/PayPal+卡价格参考$...

在 iPhone 上下载国外App

地区/国家限制App Store 会根据 Apple ID 的国家或地区限制应用下载。如果你的 Apple ID 绑定的是中国大陆,就可能无法下载 OpenAI 官方的 ChatGPT 应用,因为它在大陆 App Store 不上架。解决办法:换成美国、加拿大、香港等地区的 Apple ID。或者在现有 Apple ID 上更改地区。注册一个国外 Apple ID(推荐)比如注册 美国区 Appl...

Node.js 中的异步编程:回调与 Promise

Node.js 是一个基于 JavaScript 构建的单线程、非阻塞运行环境,它通过异步编程机制来高效处理多个操作。在执行如文件读取、API 请求或数据库查询等任务时,Node.js 不会等待这些操作完成,而是使用回调函数和 Promise 来避免阻塞主线程。 回调方式实现异步 那么当异步操作完成后,Node.js 如何知道接下来要做什么呢?这就要用到 回调函数(callback)。 回调本质上...

Selenium自动化测试入门指南

Selenium自动化测试入门指南

什么是自动化测试? 自动化测试是指利用软件工具自动执行测试用例,模拟用户操作,如打开网页、点击链接、输入文本等,并验证结果是否符合预期。 其主要优点包括: 大幅减少人工成本 测试速度快 可以在非工作时间运行 支持持续集成和交付 然而,它也存在一些局限性,例如开发成本较高、不适合快速变化的项目、依赖稳定的UI界面等。 自动化测试的应用条件 适合引入自动化测试的情况包括: 手动测试耗时且需要大量...

MariaDB Galera集群故障快速恢复指南

OpenStack控制节点采用三节点MariaDB Galera集群架构。当数据库集群因故障重启时,有时会出现Galera集群无法正常启动的问题。虽然有多种方法可以恢复数据库服务,但如何实现快速启动同时确保数据完整性呢? 通过分析日志发现,MariaDB Galera集群节点宕机时会在日志中输出以下信息: [Note] WSREP: 新集群视图:全局状态: 874d8e7e-5980-11e8-8...

二叉树基础操作实现(C语言)

二叉树基础操作实现(C语言)

二叉树遍历方法 以下为二叉树结构示例 前序访问实现: void traversePreOrder(TreeNode* node) { if (node == NULL) { printf("N "); return; } printf("%d ", node->value); trave...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。