尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Java 世界历险记:从一行 System.out.println 到整个 Spring 宇宙
Java 世界历险记从一行System.out.println到整个 Spring 宇宙你敲下 System.out.println(“Hello”)屏幕上弹出两个字。你觉得自己会 Java 了。直到有一天你打开了 JVM 的文档才发现自己连这句话是怎么跑到屏幕上的都不知道。序章一个让我重新认识 Java 的瞬间某天我写了一段再普通不过的代码javapublic class Main { public static void main(String[] args) { String a hello; String b hello; String c new String(hello); System.out.println(a b); // true System.out.println(a c); // false System.out.println(a.equals(c)); // true } }前两个输出我勉强能解释第三个输出让我彻底懵了。a c 是 false但 a.equals(c) 是 true。一个说不相等一个说相等。我盯着屏幕第一次意识到我用了这么久 Java连相等是什么意思都没搞明白。于是我决定往下挖。这一挖挖出了 JVM、字节码、内存模型、垃圾回收、Spring 宇宙……一个比我想象中庞大得多的世界。第一章Java 代码的一生——从.java到机器码你写的.java文件并不是直接跑的。它经历了一段变身之旅textMain.java ↓ javac 编译 Main.class字节码 ↓ JVM 解释/编译 机器码第一步编译成字节码bashjavac Main.java这行命令把.java编译成.class里面是字节码。字节码不是机器码也不是源代码而是一种中间语言。想看它长什么样用javapbashjavap -c Main输出text0: ldc #2 // String hello 2: astore_1 3: getstatic #3 // Field java/lang/System.out 6: ldc #4 // String hello 8: invokevirtual #5 // Method java/io/PrintStream.println原来 System.out.println(hello) 不是一行代码而是一堆指令。第二步JVM 负责翻译JVMJava 虚拟机就是那个翻译官。它有两种模式解释执行读一条字节码执行一条。即时编译JIT把热点代码编译成机器码直接跑。Java 比 C 慢那是以前。有了 JIT热点代码跑起来和 C 差不多。第三步为什么叫一次编写到处运行因为字节码是平台无关的。同一份.class在 Windows 上由 Windows 的 JVM 翻译在 Linux 上由 Linux 的 JVM 翻译。JVM 屏蔽了操作系统的差异这就是 Java 的最大卖点。第二章JVM 内存模型——程序运行时的五脏六腑JVM 在运行时会把自己的内存分成几块1. 堆Heap——最大的一块所有对象都在这里。你new出来的东西全在堆里。javaUser user new User(); // user 对象在堆里堆是线程共享的也是垃圾回收的主战场。2. 栈Stack——每个线程一个方法调用时的局部变量、方法参数、返回值都在这。javapublic void hello() { int x 1; // x 在栈里 String s hi; // s 的引用在栈里对象在堆里 }栈是线程私有的。每个线程有自己的栈方法调用就压栈方法结束就弹栈。3. 方法区Method Area——类信息类的元信息、常量、静态变量都在这。从 JDK 8 开始方法区的实现叫元空间Metaspace它在本地内存里不在 JVM 堆里。4. 程序计数器PC Register记录当前线程执行到哪条字节码。每个线程一个是 JVM 内存里唯一不会 OOM 的区域。5. 本地方法栈给 native 方法用的。这五块合起来就是 JVM 的五脏六腑。第三章垃圾回收——JVM 的自动清洁工Java 最爽的一点不用手动 free。但 JVM 怎么知道哪些对象该回收引用计数不行如果 A 引用 BB 引用 A两个都回收不了。所以 JVM 用的是可达性分析。可达性分析从 GC Roots 出发GC Roots 包括栈里的局部变量。方法区的静态变量。常量引用。JNI 引用。从这些根出发能走到的对象就是活的走不到的就是垃圾。分代回收新对象查得勤老对象查得少堆被分成两块新生代Young新对象在这回收频繁用复制算法。老年代Old活得久的对象回收少用标记-整理算法。为什么这么分因为大部分对象朝生夕死。垃圾回收器从 Serial 到 G1 到 ZGCSerial单线程简单适合小内存。Parallel多线程吞吐优先。CMS并发收集低延迟。G1分区收集平衡吞吐和延迟JDK 9 后的默认。ZGC超低延迟适合大堆。选哪个看你的场景要吞吐选 Parallel要低延迟选 ZGC。第四章Java 语言的武功秘籍Java 语言本身也有不少招式。1. 面向对象封装、继承、多态javaclass Animal { void speak() { System.out.println(...); } } class Dog extends Animal { Override void speak() { System.out.println(汪汪); } } Animal a new Dog(); a.speak(); // 汪汪多态的本质是编译时看类型运行时看对象。2. 泛型类型安全的模板javaListString list new ArrayList(); list.add(hello); // list.add(1); // 编译报错泛型只在编译期有效运行时会被擦除。javaListString a new ArrayList(); ListInteger b new ArrayList(); System.out.println(a.getClass() b.getClass()); // true这就是类型擦除也是 Java 泛型最容易被误解的地方。3. 反射运行时的透视眼javaClass? clazz Class.forName(com.example.User); Object obj clazz.getDeclaredConstructor().newInstance(); Method method clazz.getMethod(setName, String.class); method.invoke(obj, 张三);反射让你在运行时看到类的结构、调用方法、访问字段。Spring 的依赖注入、MyBatis 的映射全靠反射。4. 注解给代码贴标签javaOverride public String toString() { return hello; } Deprecated public void oldMethod() {} SuppressWarnings(unchecked) public void unchecked() {}注解本身不做任何事是处理注解的代码让它有了意义。比如 Override 由编译器检查Autowired 由 Spring 处理。5. Lambda 和 Stream函数式编程javaListString names Arrays.asList(张三, 李四, 王五); names.stream() .filter(n - n.startsWith(张)) .map(String::toUpperCase) .forEach(System.out::println);Lambda 让 Java 也能写出函数式的代码。Stream 让集合操作像 SQL 一样流畅。第五章Spring 宇宙——Java 框架的复仇者联盟如果说 Java 语言是武功那 Spring 就是门派。Spring CoreIoC 和 DIIoC控制反转对象的创建权从你手里交给 Spring。DI依赖注入Spring 把依赖注入到你的对象里。javaService public class UserService { Autowired private UserRepository userRepository; }你不用 new UserRepository()Spring 帮你 new。Spring AOP面向切面编程把日志、事务、权限这些横切逻辑从业务代码里抽出来。javaAspect Component public class LogAspect { Before(execution(* com.example.service.*.*(..))) public void logBefore(JoinPoint jp) { System.out.println(调用方法 jp.getSignature()); } }AOP 的底层是动态代理JDK 动态代理或 CGLIB。Spring MVCWeb 层javaRestController RequestMapping(/api/users) public class UserController { GetMapping(/{id}) public User getUser(PathVariable Long id) { return userService.findById(id); } }RestController GetMapping一个接口就出来了。Spring Boot把 Spring 变简单javaSpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }一行代码启动整个应用。内嵌 Tomcat自动配置开箱即用。Spring Boot 的自动配置是它最核心的魔法根据你引入的依赖自动配置相应的 Bean。Spring Cloud微服务的全家桶Eureka / Nacos服务注册与发现。OpenFeign服务间调用。Gateway网关。Hystrix / Sentinel熔断限流。Config / Nacos配置中心。Spring Cloud 让微服务不再是架构师才懂的东西。MyBatis / MyBatis-Plus / JPA持久层javaMapper public interface UserMapper { Select(SELECT * FROM users WHERE id #{id}) User findById(Long id); }MyBatis 让你手写 SQL灵活JPA 让你面向对象简洁。MyBatis-Plus 在 MyBatis 上加了 CRUD 封装开发更快。第六章Java 的家族图谱Java 不只是语言它是一个生态。Java SE标准版基础语言 核心库。Java EE / Jakarta EE企业版Servlet、JPA、EJB。Java ME微型版嵌入式。JavaFX桌面 GUI。Android移动端用 Java/Kotlin。JDK、JRE、JVM 的区别JVM虚拟机执行字节码。JREJVM 核心类库能运行 Java 程序。JDKJRE 编译器 工具能开发 Java 程序。一张图记住JDK JRE JVM。第七章那些年 Java 被吐槽的黑点1. 啰嗦java// Java public class Main { public static void main(String[] args) { System.out.println(hello); } } python# Python print(hello)Java 的仪式感确实重了点。2. 泛型擦除javaListString list new ArrayList(); list.add(hello); // 运行时你不知道 list 里是 String擦除让泛型失去了运行时信息也带来了一堆类型转换警告。3. 空指针javauser.getAddress().getCity().getName(); // 任何一环是 null就 NPENPE 是 Java 程序员的日常噩梦。JDK 14 引入了 Optional但用起来还是不如 Kotlin 的 ?. 优雅。4. 启动慢、内存大JVM 启动要几秒内存占用动辄几百 MB。这也是为什么云原生时代Go 和 Rust 开始抢 Java 的饭碗。但 Java 也在进化GraalVM 让 Java 能编译成原生镜像启动快、内存小。第八章Java 的武功心法学 Java 这么多年我最大的感悟是Java 不是一门语言而是一个体系。语言只是表层。JVM 是地基。框架是楼房。生态是城市。学 Java 的路径大概是这样的先学语法类、对象、继承、多态、集合、异常。再学 JVM内存模型、GC、类加载、字节码。然后学框架Spring、Spring Boot、MyBatis。最后学架构微服务、分布式、高并发。但最重要的不是学了多少框架而是理解为什么这么设计。为什么要有 GC因为手动管理内存太容易出错。为什么要有 IoC因为对象依赖太复杂。为什么要有 AOP因为横切逻辑太分散。每一个设计都是为了解决一个具体问题。终章回到最初的问题现在我可以回答开头那个问题了。javaString a hello; String b hello; String c new String(hello); System.out.println(a b); // true System.out.println(a c); // false System.out.println(a.equals(c)); // truea b 是 true因为 “hello” 在字符串常量池里a 和 b 指向同一个对象。a c 是 false因为 new String() 在堆里创建了一个新对象地址不同。a.equals© 是 true因为 equals 比较的是内容不是地址。一个相等背后是字符串常量池、堆、栈、引用和内容的复杂关系。这就是 Java 的底层世界你看到的每一行代码背后都有一整套机制在运转。P.S. 写完这篇文章后我又写了一次 String a hello; String b hello;然后想如果 JVM 哪天不优化了这个世界会怎样P.P.S. 但 JVM 一直在优化从解释到 JIT从 Serial GC 到 ZGC。Java 没老它一直在进化。
RELATED

相关推荐

重言式判别程序设计:栈与中缀转后缀实战指南

重言式判别程序设计:栈与中缀转后缀实战指南

简介:本资源是一份面向计算机专业本科生的数据结构课程设计实践材料,聚焦重言式判别程序的完整实现与原理剖析,解决布尔表达式逻辑恒真性自动验证这一典型算法问题。压缩包共4个文件(2个DOC文档、2个C源码)&#xff0c…

📅 2026/10/21 6:46:02
Dify实战指南:如何快速搭建大模型应用与知识库工作流

Dify实战指南:如何快速搭建大模型应用与知识库工作流

先说个实在话:市面上能让你“不写太多代码就把大模型应用搭起来”的开源平台不少,但真要上手折腾一遍,你会发现Dify的完成度确实让人服气。我前后用它在公司内部做了好几个原型项目,从简单的问答机器人到带知识库的客服助手&#…

📅 2026/10/21 6:41:02
从玩具数据集到真实项目:scikit-learn SVM分类实战与调参指南

从玩具数据集到真实项目:scikit-learn SVM分类实战与调参指南

1. 从一个玩具数据集说起:为什么选择SVM做分类入门很多人第一次接触机器学习分类任务时,都会从逻辑回归或者决策树入手,觉得它们直观、好理解。但如果你问一个在实际项目里摸爬滚打过的人,哪个分类器最值得先吃透,我大…

📅 2026/10/21 6:41:02
MORE NEWS

更多资讯

📰

PostgreSQL 查询全部函数信息:从 pg_proc 到综合模板

1. 为什么需要把数据库里的函数全部查出来:几个真实场景先讲个实际例子。我接手过一个跑了三年的业务系统,里面几十个服务共用一个 PostgreSQL 实例。某天要做数据迁移前的合规盘点,DBA 要求把所有自定义函数、触发器和存储过程全部登记造册。…

📰

汽车推荐分析系统全链路实现:爬虫、线性回归与Flask可视化

本科阶段的计算机毕业设计里,“汽车推荐分析系统”几乎是长盛不衰的经典选题。但很多同学做出来的版本,往往停留在“爬了几百条数据 画两张图表 套一个线性回归模型”的层面,答辩时最怕老师追问两类问题:一是“你这些数据怎么来…

📰

平衡膳食指南文档解读:五大类食物与三大营养素供能比落地执行

简介:这是一份面向普通大众、营养学习者及健康管理从业者的科普文档,围绕平衡膳食的内涵、重要性与现代实践展开,帮助读者理解如何通过合理搭配食物满足人体近50种营养素的全面需求。文档共1个doc文件,压缩包约21KB,内…

📰

PL/0编译器添加运算符:词法、语法到P-code虚拟机的完整改动指南

简介:编译原理课程设计资料,面向计算机专业本科生,围绕PL/0编译器的修改扩充展开,重点集中在运算符扩展和循环语句实现。内容包含基本要求与选做内容:基本部分完成、-赋值运算以及Pascal FOR语句的TO/DOWNTO两种形式&a…

📰

arping 实战:链路层定位主机与回读 MAC 地址

简介:这是一份面向网络管理员、运维工程师及网络编程学习者的 arping 工具源码资源包,聚焦以太网环境下基于 ARP 协议探测主机在线状态并获取其 MAC 地址这一典型场景。资源共 19 个文件,以 cpp 与 h 源文件为主,辅以 vcxproj、vc…

📰

Python自然语言处理入门:从分词到深度学习完整指南

简介:这份资源面向希望系统掌握中文自然语言处理的Python开发者与初学者,围绕分词、词性标注、命名实体识别、情感分析、主题建模及深度学习模型等核心主题,提供从基础概念到实战案例的完整学习路径。压缩包共42个文件,约53.58MB&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬