java系列基础知识及使用方法(内功修炼第一讲之谈谈对)
java系列基础知识及使用方法(内功修炼第一讲之谈谈对)说 Java 是解释执行这句话比较片面,也是不太准确的。我们开发出的以 .java 为后缀的源代码,会通过 javac 编译成 JVM 能够看懂的字节码,然后在运行时,通过 Java 虚拟机内嵌的解释器将字节码转换最终计算机能够看懂的机器码。JDK 其实就是 JRE 的一个超集,它提供了更多的工具,比如编译器,各种诊断工具等。还有 JDK 包含的一些工具,如编译器,运行时环境,安全工具,性能诊断(线上线程死锁,如何锁定问题?),监控工具等。日常开发中,我们会经常接触到 JRE(java runtime environment) 或者是 JDK (java development kit)。JRE 也就是 java 运行时环境,它包含了 JVM 和 java 类库以及其他一些模块。题外话:很多 java 开发者不是很清晰 JRE 和 JDK 之间的关系。
本系列博文将以面试题为切入点,带你深入 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