开篇:为什么需要集合框架?
学 Java 的第一天,你一定写过这样的代码:
int[] scores = new int[5];
学 Java 的第一天,你一定写过这样的代码:
int[] scores = new int[5];
如果 Java 面试只能考一道题,那大概率就是 HashMap。不夸张地说,HashMap 几乎是每场 Java 面试的"必考嘉宾"。原因很简单:它短短几千行代码里,浓缩了数组、链表、红黑树、哈希算法、位运算、扩容策略等一系列数据结构与算法的精华,堪称一部"微型教科书"。
更重要的是,HashMap 的设计思路直接影响着我们的日常编码。你每天写的 map.put(key, value) 背后到底发生了什么?为什么多线程下它会出问题?什么时候该换成 ConcurrentHashMap?搞懂这些问题,不仅面试能过关,日常写代码也能少踩很多坑。接下来,我们就从底层原理出发,把 Map 家族彻底拆解一遍。
想象你是一个厨师。泛型就像一套万能模具,不管做蛋糕还是饼干,模具的形状保证了产品的规格;反射就像X光透视,能在运行时看穿任何对象的内部结构;注解就像食品标签,虽然不影响味道,但告诉处理系统该怎么对待这个食品。
这三个特性撑起了 Spring、MyBatis 等框架的底层魔法。理解它们,你就能看懂框架源码中那些"玄学"代码。
在 JDK 5 之前,集合里什么都能塞,取出来的时候全靠强转,错了就是运行时炸弹:
// JDK 5 之前的写法
List list = new ArrayList();
list.add("hello");
list.add(123); // 编译不报错!
String s = (String) list.get(1); // 运行时 ClassCastException
你在淘宝下了一个订单,订单对象在服务器 A 的 JVM 内存里。但处理发货的是服务器 B,它有自己的 JVM。一个 Java 对象怎么从 A 飞到 B?答案就是序列化——把内存中的对象变成一串字节,通过网络传过去,对面再还原成对象。
而数据在传输过程中怎么高效地读和写,就是 IO 体系要解决的问题。再加上 Java 让框架可插拔的 SPI 机制,这三块知识合在一起,构成了 Java 网络编程和框架设计的基础。
在 Java 的世界里,如果要评选"最常用的类",String 一定高票当选。从你写下第一行 System.out.println("Hello World") 开始,字符串就如影随形——拼接日志、构建 SQL、传递参数、校验密码,几乎所有业务逻辑都离不开它。
但正因为太常用,很多人对 String 的理解停留在"会用"层面,却忽略了它背后精妙的设计:为什么它是不可变的?常量池到底怎么工作?== 和 equals 为什么有时结果不同?再加上基本类型与包装类的自动拆装箱"暗坑"、浮点数的精度陷阱……这些问题串起来,就构成了 Java 类型系统最核心也最容易踩坑的知识图谱。这篇文章,我们就来一次性讲透。
很多人对 Java 的印象还停留在"啰嗦"二字——写一个简单的数据类要几十行,处理集合离不开 for 循环,并发编程更是让人头大。但从 2014 年的 JDK 8 开始,Java 就像一辆老牌跑车换上了涡轮增压引擎,每半年一个版本,每个版本都在让代码变得更简洁、更安全、更高效。
本文将带你从 JDK 8 一路走到 JDK 21,用真实的代码对比来感受每一代新特性带来的变化。不求面面俱到,但求每个特性你都能看完就用。如果你还在写 JDK 8 之前风格的代码,读完这篇文章,你会发现自己错过了太多好东西。
如果把写程序比作搭积木,面向过程就像是按照说明书一步步把积木拼好——先拿红色块,再拿蓝色块,然后插到底板上。你的脑子里想的全是"下一步该干什么"。
而面向对象更像是先造出一个个"积木工厂":这个工厂专门生产红色块,那个工厂专门生产蓝色块,每个工厂知道自己该怎么运作。你要搭什么东西,只需要跟这些工厂打交道就行了。
Java 从第一天起就选择了面向对象这条路。它把世界上的一切都看成"对象"——你的银行账户是对象、购物车是对象、甚至一条日志也是对象。每个对象有自己的属性(数据)和行为(方法),对象之间通过消息传递来协作。