答案,真不一定!
虽然 Java 在诞生之初,设计的主要目标就是跨平台,并且也做了很多事情来让这个成为可能,也是很多年来Java的一个重要优势。但随着技术的发展和应用场景的变化,Java的跨平台特性并不是在所有情况下都是绝对必要的。
Java 是如何实现跨平台的?
平台无关性就是一种语言在计算机上的运行不受平台的约束,一次编译,到处执行(Write Once, Run Anywhere)。也就是说,用Java创建的可执行二进制程序,能够不加改变的运行于多个平台。
Java通过JVM(Java虚拟机)实现了平台无关性。JVM是一个平台相关的软件,它为Java程序提供了一个统一的运行环境。只要设备上安装了相应平台的JVM,Java程序就可以在任何平台上运行,不需要做任何修改。这就是“一次编写,到处运行(Write Once, Run Anywhere, WORA)”的理念。
静态编译技术介绍
然而,在当前出现了众多静态编译技术。
例如:
预先编译(AOT,Ahead-Of-Time Compilation):这涉及到将Java字节码提前转换成特定平台的机器码,而不是依赖于运行时的即时编译(JIT)。这样的方法有助于缩短JVM的启动时间,并优化程序的执行效率。
GraalVM的原生镜像(Native Image):GraalVM提供了一种机制,可以将Java应用程序转换成所谓的“原生映像”,这种映像能够在操作系统层面直接运行,无需JVM的介入。
无论是通过AOT编译将代码提前转换成机器码,还是利用Native Image技术消除对JVM的依赖,最终生成的程序都是与特定平台绑定的。
什么是AOT编译?
AOT(Ahead-Of-Time Compilation)编译是指在程序运行之前,将Java字节码编译成特定平台的机器码。这种方式可以减少JVM启动时间并提高程序运行效率。
为什么Java要走回头路?
Java之所以采用AOT和Native Image等技术,牺牲一定的平台无关性,主要是为了适应云原生和Serverless的环境。在这些环境中,平台无关性的重要性有所下降,而性能、资源利用率和部署的简便性变得更加重要。
特定平台的机器码:AOT编译生成的是针对特定操作系统和硬件架构的机器码。这意味着编译后的程序只能运行在与编译目标相匹配的平台上,与Java字节码的跨平台特性不同。
缺少JVM抽象层:Java的跨平台特性很大程度上依赖于JVM提供的抽象层,它使得字节码可以在任何安装了相应JVM的平台上运行。而AOT编译绕过了JVM,直接生成机器码,因此失去了这种抽象层。
部署复杂性:当应用程序使用AOT编译后,可能需要为每个目标平台编译一个特定版本的程序。这增加了部署的复杂性和工作量,因为开发者需要管理多个版本的应用程序。
维护成本:随着平台数量的增加,维护多个版本的应用程序变得更加困难和昂贵。这与Java平台无关性带来的便利性形成了对比。
性能和资源权衡:AOT编译通常用于提高程序的性能和减少启动时间,但这是以牺牲平台无关性为代价的。在某些场景下,这种权衡是可接受的,尤其是在性能要求高、平台相对固定的环境中。
云原生和容器化:在云原生和容器化环境中,应用程序通常运行在隔离的环境中(如Docker容器或Kubernetes集群),这些环境可以隐藏底层硬件和操作系统的差异。在这种情况下,AOT编译带来的平台依赖性问题不那么明显。