编译后的成果物层面
同样的C\C++源文件文件,经过不同的计算机硬件(x86平台、arm、AMD)、不同的操作系统(Linux\mac\windows etc.)上的编译器编译后,生成了不同的机器码,是互不通用的。
而Java源码(.java)经过编译后,生成了class字节码文件,通过不同平台上的JVM(Java 虚拟机)都可以解释执行。JVM掩盖了计算机硬件和操作系统的差异,对class提供了统一的执行接口,这就是java为啥能跨平台的原因。
在面向对象设计原则中,有个原则叫“开闭原则”(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。java的跨平台性就是遵守了这一原则。它所使用的设计模式,是适配器模式。
#TODO: 如果深入理解这个问题,可能涉及到很多层面(编译原理、操作系统提供的API、操作系统内核提供的系统调用、CPU指令集),不同的操作系统中的函数库提供了不同的系统API(应用程序接口);不同的编译器和操作系统定义了不同的ABI(应用二进制接口);不同的CPU架构,有着不同的指令集。机器码就是指令集上指令对应的二进制(0和1组成的序列)表示。
以openjdk8为例
openjdk 是如何屏蔽操作系统和硬件的不同的呢?可以到jdk的源码中找到答案:
源码网址:jdk8u/jdk8u/hotspot: 00df30073cfa /
在源码目录的os和cpu中对应的代码,就是用来分别对操作系统和计算机硬件做屏蔽的
在学jvm的时候,我们很多人可能都见过下面这个图。下图中的Native Method Interface部分,就对应了上图中src目录下一部分的源码,所以如果想学好jvm,读源码是一个好方法。
首先我们来看看上面这个图的“Class File”这块,class文件是以什么样的形态被Class Loader SubSystem加载的。
Java的class文件是什么
Class文件是jvm认识的一种字节码文件,里面的地址都是逻辑的地址。最后需要运行在操作系统中,操作系统只能识别真实的物理地址。此时需要动态链接(这个过程就是将逻辑地址变成物理地址),就是在运行时动态地绑定对象、对象地址。
此外,它还是一组以8位字节为基础单位的二进制流(容错性低,错一个字节则整个class文件不可用;节省空间\可以不用定义传输的格式,比如json,xml,而直接用二进制流传输数据),各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何的分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必需数据。
Class字节码文件只有两种数据类型:无符号数(u)和表(info)。
Class文件的规范可以在oracle的 jvm规格说明书 的第4节(4. The class File Format)中查看:
u4:4字节无符号数,u2类似
将一个.class文件用sublim打开,查看16进制形式,这个16进制形式按上面的ClassFile Structure对应解析例如:
package main.test;
public class classtest {
public static void main(String[] args) {
int a = 11;
int b = 22;
int c = a+b;
System.out.println(c);
}
}
生成class字节码后用sublim打开
cafe babe 0000 0034 0024 0a00 0500 1709
0018 0019 0a00 1a00 1b07 001c 0700 1d01
0006 3c69 6e69 743e 0100 0328 2956 0100
0443 6f64 6501 000f 4c69 6e65 4e75 6d62
6572 5461 626c 6501 0012 4c6f 6361 6c56
6172 6961 626c 6554 6162 6c65 0100 0474
6869 7301 0015 4c6d 6169 6e2f 7465 7374