谈谈对 Java 平台的理解

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

本系列博文将以面试题为切入点,带你深入 Java 核心内容,提升 Java 内功修为。

面试官:谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗?

1.对 Java 平台的理解

针对 Java 平台的理解,我们可以从多方面简明扼要的谈及一下,比如:Java 是一门面向对象的高级语言,具有 Compile once, run anywhere(一次编译,到处运行) 的跨平台的特性;Java 语言的特性包括泛型, lambda 特性等;基础类库包括常用的 utils 包下面的集合,还有 IO/NIO, 网络,并发,安全等基础类库等。

在谈谈 JVM 的一些基础概念和机制,这其中包括 Java 的类加载机制,常用版本 JDK(如 JDK8) 内嵌的 Class-Loader, 例如 Bootstrap, Application 和 Extension Class-Loader(拓展类加载器);类的加载的大致过程:加载 -> 验证 -> 连接 -> 初始化;自定义 Class-Loader 等。还可以说说垃圾回收的基本原理,最常见的垃圾回收器,如 SerialGC、Parallel GC、 CMS、 G1 等。

还有 JDK 包含的一些工具,如编译器,运行时环境,安全工具,性能诊断(线上线程死锁,如何锁定问题?),监控工具等。

日常开发中,我们会经常接触到 JRE(java runtime environment) 或者是 JDK (java development kit)。JRE 也就是 java 运行时环境,它包含了 JVM 和 java 类库以及其他一些模块。

题外话:很多 java 开发者不是很清晰 JRE 和 JDK 之间的关系。

JDK, 其实就是 JRE 的一个超集,它提供了更多的工具,比如编译器,各种诊断工具等。

2.Java 究竟是不是解释执行呢?

说 Java 是解释执行这句话比较片面,也是不太准确的。我们开发出的以 .java 为后缀的源代码,会通过 javac 编译成 JVM 能够看懂的字节码,然后在运行时,通过 Java 虚拟机内嵌的解释器将字节码转换最终计算机能够看懂的机器码。

但是常见的 JVM , 比如我们生产环境经常使用的 Oracle JDK 提供的 Hotspot JVM, 都提供了 JIT(just in time) 编译器,也就是动态编译器,JIT 能够将程序中那些热点代码编译成机器码(大部分程序都是小部分的热点代码耗费了系统的大多数资源),这种情况下,所说的部分热点代码就属于编译执行的范畴,而不是解释执行。

备注:说到这里,也许还是有很多人很迷糊,到底解释执行编译执行有啥区别?

举个形象的栗子,拿翻译官翻译的场景说事,解释执行就好比同声传译,而编译执行就好比提前翻译好,到时候直接放录音即可。

3.解释执行和编译执行知识面深入

我们都知道,Java 通常分为编译期和运行时。但是 Java 的编译和 C/C++ 又有不同的意义,我们说的编译通常是通过 javac 命令将 java 源代码编译成 .class 字节码文件,而不是能够直接运行的机器码。

在运行时,JVM 会通过类加载器(Class-Loader)加载字节码,解释执行或者编译执行。在主流的 JDK 版本(JDK 8)中, 实际上采用的是混合编译模式,即解释执行 + 编译执行。

另外,Java 虚拟机启动时,我们可以指定不同的参数对运行模式进行选择。比如,指定 -Xint, 就是告诉 JVM 只进行解释执行,而不使用编译执行,这种模式抛弃了 JIT 带来的性能优势。对应的,我们还可以通过 -Xcomp 参数,告诉 JVM 关闭解释执行。我们可能会觉得这种模式,性能较高,那可未必。-Xcomp 会导致 JVM 启动变慢很多。

除了上面谈到的解释执行和编译执行,还有一种叫做 AOT(Ahead-of-Time Compilation), 直接将字节码编译成机器码,这样避免了 JIT 预热等方面的开销,JDK 9 中就映入了这种 AOT 特性,并且新增了 jaotc 工具。通过下面的命令把某个类或者某个模块编译成 AOT 库。

jaotc --output libHelloWorld.so HelloWorld.class
jaotc --output libjava.base.so --module java.base

然后,你就可以在启动的时候指定了:

java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld