Java 知识体系:从语言基础到并发、JVM 与 IO
这份知识体系按「语言基础 → 集合 → 并发 → JVM → IO → 新特性」组织 Java 模块的全部文章。它不是目录堆砌,而是一张学习地图:每个主题解决什么问题、依赖哪些前置、按什么顺序推进,都有明确答案。 模块全景 主题 解决什么问题 主要前置 Java 基础 语法、面向对象、泛型、反射、代理、序列化等语言机制 无 Java 集合 容器选型、源码实现与复杂度权衡 基础(泛型、equals/hashCode) Java 并发 线程、锁、JMM、CAS、AQS、线程池的正确使用 基础 + 集合 JVM 内存区域、类加载、垃圾回收与线上排障 基础,配合并发更佳 Java IO BIO/NIO/AIO、多路复用与 IO 相关设计模式 基础,线程模型涉及并发 Java 新特性 Java 8 之后各版本的语言、标准库与 JVM 演进 按项目版本选学 学习顺序与依赖关系基础是唯一的硬前置:值传递、泛型擦除和反射贯穿后面所有模块。集合紧随其后,因为 equals/hashCode 约定、泛型边界都要在 Hash...
Java 反射、类加载器与 JDK 新特性
这是入门系列的收官篇,也是通往框架世界的大门:Spring、MyBatis 的灵魂都是反射与动态代理。把类加载和反射吃透,再回顾 JDK 5 到 8 的语言演进,这个系列的知识版图就完整了。 本篇目标读完本篇你应该能够:说出类加载的三步流程与六种触发时机;描述三层类加载器与双亲委派的运作方式;用三种方式获取 Class 对象;用反射操作构造器、方法、字段;说清反射的价值与代价;盘点 JDK 5~8 的代表性特性。 类加载:从 .class 文件到 Class 对象程序用到某个类时,如果它还没进内存,JVM 会完成三步:加载(把 .class 文件读入内存,创建对应的 Class 对象)、连接(验证字节码合法性、为静态变量分配内存并设默认值、把符号引用解析为直接引用)、初始化(执行静态代码块和静态变量赋值,也就是我们熟知的类初始化)。 触发加载的时机有六种:创建实例(new)、访问或赋值静态变量、调用静态方法、反射(Class.forName)、初始化子类(父类会先加载)、java 命令运行主类。记住规律:第一次”主动使用”时加载,且整个生命周期只加载一次——这正是上一篇饿汉式...
Java 网络编程:UDP、TCP 与 Socket
前面学的 IO 是程序和文件对话,本篇让程序和网络另一端的程序对话。网络编程是分布式世界的地基,今天的一切微服务、RPC 最终都落在 Socket 上,这一课值得慢慢啃。 本篇目标读完本篇你应该能够:说清网络通信三要素各自解决什么寻址问题;用 InetAddress 操作 IP;用 DatagramSocket 完成 UDP 收发并解释它”快但不可靠”的原因;用 ServerSocket/Socket 写出 TCP 客户端与服务端;把单连接服务端改造成每连接一线程的并发模型,并说出它的瓶颈在哪。 网络通信三要素两台机器上的程序要通信,需要回答三个层层递进的问题: IP 地址——找到哪台机器。 网络中每台设备的唯一标识。IPv4 由 4 个字节组成(约 42 亿个,2011 年已分完),IPv6 用 8 组十六进制数解决地址枯竭。127.0.0.1 是本地回环地址,数据不出网卡,是学习阶段的最佳拍档;ping 命令用来测试两台机器是否连通。 端口——找到机器上哪个程序。 一台机器同时跑着数据库、Web 服务、聊天软件,IP 只能定位到机器,端口(0~65535)才能定...
Java 并发工具、设计模式与 GUI 事件
上一篇解决了”线程怎么抢”,本篇解决”线程怎么合作”:wait/notify 通信、Lock 锁、线程池是并发进阶的三件套;再配上单例模式的线程安全演进史和两个常用设计模式,入门到中级之间的桥就搭好了。 本篇目标读完本篇你应该能够:用 wait/notify 写出正确的生产者消费者模型;说出 Lock 相对 synchronized 的改进点;解释为什么需要线程池并用 Executors 提交任务;写出饿汉式、懒汉式、双重检查锁三种单例并讲清它们的线程安全性;理解简单工厂、工厂方法、适配器三种模式各解决什么问题。 线程通信:wait 与 notifysynchronized 保证的是互斥,但线程之间还需要协作。经典场景是生产者消费者:生产者往缓冲区放数据,满了就等;消费者取数据,空了就等;双方互相唤醒。 class Buffer { private int data; private boolean hasData = false; public synchronized void produce(int value) thro...
Java 并发:线程创建、同步与死锁
并发是 Java 从中级开始的分水岭:单线程世界里的直觉,在多线程下会接二连三失效。本篇把线程的创建、调度、协作与同步一次讲透,并亲手制造一次死锁,为后续并发工具篇打底。 本篇目标读完本篇你应该能够:说清进程与线程、并行与并发的区别;用两种方式创建线程并解释为什么推荐 Runnable;画出线程生命周期的状态流转;用 sleep、join 控制线程协作;用 synchronized 的两种形态解决线程安全问题;解释死锁产生的四个必要条件。 进程与线程:资源分配与调度的两级单位进程是操作系统分配资源的最小单位,线程是 CPU 调度的最小单位。启动一个 JVM 就是启动一个进程,进程内至少跑着主线程和垃圾回收线程——所以你写的第一个 HelloWorld 程序其实已经是多线程的。 关键区别在于资源共享方式:进程之间内存相互独立,切换代价高;同一进程内的线程共享堆内存和方法区,每个线程只独占自己的虚拟机栈和程序计数器。共享内存带来了通信的便利,也埋下了本篇后半段的线程安全问题。 顺带区分两个高频词:并行是多个任务在多核上真正同时执行,好比左手右手各操作一台电脑;并发是单核靠时间片轮...
Java 递归与经典算法练习
递归是入门系列的第一个”思维门槛”:代码看上去只有几行,执行过程却在方法调用栈里层层深入。本篇作为系列进阶收尾的第一课,从调用栈讲清递归的本质,再用五个经典问题把递归思维练到肌肉记忆。 本篇目标读完本篇你应该能够:说出递归执行时 JVM 栈上发生了什么;用”递推关系、出口、问题规模”三要素拆解任何递归问题;独立写出阶乘、斐波那契、目录遍历、汉诺塔的递归实现;并掌握约瑟夫环的模拟解与公式解两种打法。 递归的执行本质:方法调用栈递归不是语法糖,而是栈结构的自然应用。Java 中每次方法调用,JVM 都会在当前线程的虚拟机栈上压入一个栈帧,存放局部变量、操作数栈和返回地址;方法返回时栈帧弹出。递归不过是”方法调用自己”,每调用一次就多压一帧,直到触及出口再逐层弹栈返回。 以 factorial(3) 为例,栈上的过程是: public static long factorial(int n) { if (n == 1) { // 出口:最小问题直接给答案 return 1; } return n * f...
Java IO:序列化、打印流与 Properties
对象也能写进文件、跨网络传输——靠的就是序列化。本篇讲透序列化的规则与版本兼容陷阱,再补齐打印流、随机访问流和 Properties 这几块 IO 拼图。 本篇目标 理解序列化/反序列化的概念,掌握 Serializable、serialVersionUID、transient 三大规则 学会序列化流读写多个对象的两种技巧 会用打印流 PrintWriter、数据流和随机访问流 RandomAccessFile 用 Properties 读写配置文件 序列化是什么序列化(Serialize)就是把内存中的对象转成字节序列写出去,持久化到文件或发往网络;反序列化则反过来,把字节序列还原成对象。JDK 提供的工具是一对”对象流”:ObjectOutputStream 用 writeObject() 把对象写出,ObjectInputStream 用 readObject() 把对象读回。 // 写出(序列化)ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("demo/p...
Java IO:字符流、编码与装饰模式
字符流与字节流的分水岭只有两个字:编码。本篇把编码表、乱码成因、转换流讲透,再借缓冲流看清 Java IO 的装饰器设计。 本篇目标 理解字符流的本质是”字节流 + 编码表”,弄清 GBK / UTF-8 的差异与乱码成因 掌握 FileReader / FileWriter 与转换流 InputStreamReader / OutputStreamWriter 的分工 用 BufferedReader 的 readLine() 和 BufferedWriter 的 newLine() 按行读写文本 看懂 Java IO 的装饰器模式,会解读层层包装的”流链” 字符流是什么字节流读文本有个尴尬:一个中文占多个字节,一次只读一个字节就可能把汉字”劈成两半”,打印出来就是乱码。字符流解决了这个问题:read() 一次读一个字符,底层自动按编码表把连续的若干个字节拼成一个完整的字符返回。 所以字符流不是凭空多出来的东西,它的工作流程是:读的时候先读字节,再按编码表转成字符;写的时候先把字符按编码表转成字节,再写出去。一句话:字节流 + 编码表 ...
Java IO:字节流与缓冲流
IO 是程序与外部设备之间的数据管道。本篇从流的分类讲起,吃透字节流的读写套路,并弄清缓冲流为什么快——答案是减少系统调用次数。 本篇目标 理解 IO 流的两个分类维度:流向(输入/输出)与数据单位(字节/字符) 掌握 FileInputStream / FileOutputStream 的读写与文件复制 讲清缓冲流提速的真正原因 学会用 try-with-resources 优雅地关闭资源 IO 流的分类IO 流处理的是设备之间的数据传输,比如内存与硬盘、程序与网络。Java 里所有操作流的类都在 java.io 包下。分类有两个维度: 按流向分:输入流(读进程序)、输出流(从程序写出)。记住方向永远以”程序”为参照物:对程序来说是”拿进来”的就是输入。 按数据单位分: 字节流:以字节(8bit)为单位读写,可以操作任何文件——图片、音频、视频在硬盘上都是字节 字符流:以字符为单位读写,只能操作纯文本,下一篇专门讲 四个抽象父类构成了整个 IO 体系的骨架:InputStream、OutputStream(字节流),Reader、Wr...
Java 异常处理与 File 类
程序运行出错时,Java 不会直接崩溃,而是抛出一个”异常对象”来描述到底发生了什么。本篇把异常体系和 File 类的文件操作这两块基础一次讲透,它们是后续 IO 学习的地基。 本篇目标 看懂 Throwable / Error / Exception 的继承体系,分清受检异常与非受检异常 掌握 try-catch-finally 的执行细节,避开 finally 中 return 的陷阱 分清 throw 与 throws 的分工,会定义自己的业务异常 用 File 类完成文件、目录的创建、判断、遍历和按名过滤 异常体系:一张继承图Java 中所有”程序的问题”都继承自 Throwable,它有两个儿子: Error:JVM 层面的严重问题,比如内存溢出(OutOfMemoryError)、栈溢出(StackOverflowError)。这类问题程序无能为力,只能听天由命,也没法用 catch 补救。 Exception:程序可以处理的异常。它又分两支: RuntimeException 及其子类:非受检异常(运行时异常),如 NullPointer...