深入解析Java基础之基础
前言
在之前我写过一篇专门讲解JVM的文章,大家看完这篇可以专门去看一下那篇,这篇主要是讲框架以及全面的看待JDK、JRE、JVM之间的关系
尽管我们在使用Java,但是最最最基础的知识还不太了解,这篇就主要从Java核心特点、优劣势、JDK/JRE/JVM三者的定义与关系、Java完整执行流程、半编译半解释特性这五个核心维度来讲解
一、Java核心特点
大家一定听说过Java的设计理念就是“Write Once, Run Anywhere”(一次编写,到处运行),其核心特点围绕这一理念展开,每个特点都有底层逻辑支撑,而非单纯的表面描述:
1.跨平台性(核心特点)
这是Java最具辨识度的特点,核心原理是「JVM的中间层隔离」——Java程序不直接编译成操作系统可执行的机器码,而是编译成中间态的字节码(.class文件),再由不同操作系统对应的JVM(Windows版JVM、Linux版JVM、macOS版JVM)将字节码解释为本地机器码执行。
关键点:跨平台的不是Java代码,而是「字节码」;JVM是跨平台的核心载体,不同系统的JVM实现不同,但都能识别统一的字节码,这也是“一次编译,到处运行”的本质。
2. 面向对象(OOP)
Java是纯面向对象语言(除基本数据类型外,所有元素都是对象),核心三大特性:封装、继承、多态,同时支持抽象类、接口,从设计上引导开发者进行模块化、可复用的代码编写。
补充:Java不支持多重继承(避免菱形继承冲突),而是通过接口实现多继承的效果,这是Java面向对象设计的一个重要取舍。
3. 安全性高
Java从设计之初就注重安全性,核心保障有三点:① 字节码校验机制(JVM加载.class文件时,会校验字节码的合法性,防止恶意代码注入);② 沙箱机制(限制程序的访问权限,比如Applet程序不能访问本地文件系统);③ 垃圾自动回收(避免手动管理内存导致的内存泄漏、野指针等安全问题,对新手很友好)。
4. 平台无关性(延伸特性)
除了跨平台,Java的平台无关性还体现在:API接口统一(不同系统的Java核心类库接口一致)、数据类型大小固定(比如int在任何系统都是32位,而C/C++中int大小随系统变化),避免了因平台差异导致的代码适配问题。
5. 垃圾自动回收(GC)
Java不需要开发者手动分配、释放内存(对比C/C++的malloc/free),而是由JVM内置的垃圾回收器(GC)自动识别并回收不再使用的对象内存,降低了内存管理的复杂度,减少了内存泄漏风险。
补充:GC并非实时回收,而是在内存达到一定阈值或程序空闲时触发,开发者可以通过System.gc()建议JVM执行GC,但无法强制触发。
6. 多线程支持
Java内置多线程机制,通过Thread类、Runnable接口、Callable接口等,轻松实现多线程编程,且JVM提供了线程调度、同步锁(synchronized,这个在之前的文章里面也详细的讲解过,大家有兴趣可以去看看)、volatile关键字等工具,简化了多线程开发的复杂度(但也需要注意线程安全问题)。
二、Java优劣势
结合Java的特点,优劣性非常鲜明,尤其在企业级开发场景中,优势更为突出,劣势也多与具体应用场景相关,而非语言本身的缺陷。
1. 优势
跨平台性突出:一次编译,多平台运行,大幅降低跨系统开发、部署的成本,尤其适合企业级应用(需部署在不同服务器系统)。
生态完善:经过近30年的发展,Java拥有庞大的生态体系,无论是框架(Spring、SpringBoot、MyBatis)、中间件(Redis、Kafka、Dubbo),还是工具类(Apache Commons、Guava),都非常成熟,能覆盖绝大多数开发场景。
安全性高:字节码校验、沙箱机制、GC等特性,让Java程序在运行过程中更稳定、更安全,适合开发金融、电商等对安全性要求高的系统。
可扩展性强:面向对象的设计、模块化开发,以及丰富的框架支持,让Java程序能够轻松应对业务迭代,便于后期维护和扩展。
人才储备充足:Java是全球使用最广泛的编程语言之一,开发者基数大,招聘、学习、问题排查都更便捷。
2. 劣势
运行效率低于编译型语言:由于Java是半编译半解释语言,存在字节码解释为机器码的过程,运行效率略低于C/C++等纯编译型语言(但现代JVM的JIT即时编译已大幅弥补这一差距)。
内存占用较高:Java程序运行时,JVM会占用一定的内存(用于运行时数据区、GC等),相比Python、Go等语言,内存消耗相对较大。
语法相对繁琐:对比Python、JavaScript等语言,Java的语法更严谨、繁琐(比如必须定义类、main方法才能运行),入门门槛略高。
移动端生态弱化:随着Flutter、React Native等跨平台框架的兴起,Java在移动端(Android)的主导地位有所下降,虽然Android开发仍以Java/Kotlin为主,但生态热度不及以往。
三、JVM 、JRE、JDK
很多开发者分不清JVM、JRE、JDK的区别,甚至认为三者是一回事,其实它们是层层包含、各司其职的关系,核心逻辑是“开发→运行→底层执行”的分工,下面逐一拆解定义、组成及关系。
1. JVM(Java Virtual Machine,Java虚拟机)—— 底层执行核心
(1)定义
JVM是一个抽象的、软件层面的“虚拟计算机”,是Java程序运行的底层核心载体,本质上是一段运行在操作系统上的程序,负责将Java字节码解释(或编译)为本地机器码并执行。
(2)核心组成
类加载器(ClassLoader):负责加载.class字节码文件到JVM内存中,验证字节码合法性,是JVM执行的第一步(注意:类加载器属于JVM,而非JRE)。
运行时数据区:JVM的内存空间,分为方法区、堆、虚拟机栈、本地方法栈、程序计数器5个部分,用于存储程序运行时的变量、对象、方法等数据(后续可单独拆解内存模型)。
执行引擎:核心模块,负责将字节码翻译成本地机器码并执行,分为解释器(逐行解释字节码)和JIT即时编译器(将热点代码编译成机器码缓存,提升效率)。
本地方法接口(JNI):用于调用本地操作系统的方法(比如访问本地文件、硬件),弥补Java无法直接操作底层硬件的不足。
垃圾回收器(GC):负责回收运行时数据区中不再使用的对象内存,避免内存泄漏,核心算法有标记-清除、复制、标记-整理等。
(3)关键注意点
JVM不能单独安装和使用,必须依赖JRE或JDK,因为JVM本身只负责执行字节码,而字节码运行需要Java核心类库的支持(比如String、List等类),JVM无法单独提供这些类库。
2. JRE(Java Runtime Environment,Java运行环境)—— 运行Java程序的最小环境
(1)定义
JRE是运行Java程序所必需的环境集合,面向的是“普通用户”或“部署环境”,只负责运行已编译好的Java程序,不提供任何开发相关的工具。
(2)核心组成
JRE = JVM + Java核心类库(rt.jar等) + 本地方法库
JVM:提供字节码的执行能力,是JRE的核心。
Java核心类库:包含Java基础API(比如java.lang、java.util、java.io等包),是Java程序运行的基础,比如String类、集合类、IO流等,都来自核心类库。
本地方法库:配合JNI,提供Java程序调用本地系统方法的支持。
(3)使用场景
如果只需要运行别人写好的Java程序(比如jar包、Java桌面程序),安装JRE即可,不需要安装JDK(比如服务器部署Java项目,只需要JRE)。
3. JDK(Java Development Kit,Java开发工具包)—— 开发Java程序的完整工具包
(1)定义
JDK是Java开发必备的完整工具包,面向的是“Java开发者”,不仅包含了运行Java程序的JRE,还提供了编译、调试、监控等开发所需的工具,既能开发Java程序,也能运行Java程序。
(2)核心组成
JDK = JRE + 开发工具集
常用开发工具:
javac:Java编译器,负责将.java源代码编译成.class字节码文件(核心开发工具)。
java:Java运行命令,负责启动JVM,加载字节码并执行程序。
jar:打包工具,将多个.class文件、资源文件打包成jar包(便于部署和分发)。
jps:JVM进程查看工具,用于查看当前运行的Java进程。
jmap、jconsole、jvisualvm:JVM监控和调试工具,用于排查内存泄漏、性能瓶颈等问题。
(3)使用场景
开发Java项目(无论是后端、桌面还是Android),必须安装JDK,因为需要使用javac编译源代码,使用调试工具排查问题。
4. 三者核心关系
层级包含关系(从大到小):JDK ⊃ JRE ⊃ JVM
JDK包含JRE:JDK自带一套完整的JRE,所以安装了JDK后,不需要再单独安装JRE(JDK的jre目录就是内置的JRE)。
JRE包含JVM:JRE将JVM作为核心组件,同时提供核心类库和本地方法库,让JVM能够正常执行字节码。
JVM是最小核心:JVM只负责执行字节码,没有JRE提供的核心类库,JVM无法运行任何完整的Java程序(比如没有String类,就无法处理字符串)。
图片来源于网络:
通俗比喻(便于记忆):
JVM = 汽车发动机(只负责运转,没有其他零件无法行驶);
JRE = 完整汽车(发动机+车身、轮胎、方向盘等基础零件,能正常行驶);
JDK = 汽车4S店+完整汽车(既能开车,还能修车、改装、生产新车,对应开发、调试、编译)。
四、Java执行流程
编写.java源代码 → JDK的javac编译 → .class字节码 → 启动JVM → 类加载器加载字节码 → 执行引擎将字节码翻译成机器码 → CPU执行 → 程序结束 → JVM释放资源。
五、Java是半编译半解释语言
Java结合了编译型语言和解释型语言的优势,既保证了跨平台性,又兼顾了运行效率
1.编译语言、解释语言
(1)编译型语言(如C/C++):在程序执行前,源代码一次性全部编译成操作系统可执行的机器码,运行时直接执行机器码,运行效率高,但无法跨平台(Windows编译的机器码,不能在Linux上运行)。
(2)解释型语言(如Python、JavaScript):源代码不提前编译,运行时逐行解释成机器码并执行,跨平台性好,但运行效率低(逐行解释需要反复翻译)。
2.Java的半编译半解释原理
Java的执行过程分为“编译阶段”和“解释阶段”,两者结合,形成了半编译半解释的特点:
(1)编译阶段(提前做,只做一次)
通过JDK的 javac 工具,将.java源代码编译成.class字节码文件,这个过程是“一次性编译”——只要源代码不变,就不需要重复编译,编译后的字节码是跨平台的(与操作系统无关)。
注意:这里的“编译”不是直接翻译成机器码,而是翻译成中间态的字节码,这是Java与纯编译型语言的核心区别。
(2)解释阶段(运行时做,按需执行)
程序运行时,JVM的执行引擎会将.class字节码逐行解释成当前操作系统的机器码,然后交给CPU执行,这个过程是“实时解释”——每执行一行字节码,就解释一行机器码。
注意:解释阶段是与操作系统相关的,不同系统的JVM解释出的机器码不同,这也是Java跨平台的关键。
