项目的 Java 版本该怎么设置?

作为一个 Android 开发,走出第一步往往是很困难的,因为要面临巨复杂的环境配置问题,一个是 gradle 与 AGP 之间纠缠不清的关系,另一个就是 java 版本相关的各种配置。今天我们就回归基础,一起梳理下 java 版本相关的各种配置是为了什么。

基础知识

我们知道,Java/Kotlin 语言需要由源代码(.java / .kt 文件)编译成字节码存放在 .class 文件中。Android 还会打包成 dex 文件,最终运行在虚拟机上。

Java 语言在不断发展,每个新版本都会引入新的语言特性和语法,以便开发者编写功能更强大的程序。这些新增的语言特性都只存在于源代码中,被称为 Java 语言源代码特性。例如,Java 8 增加了 lambda 表达式。

class 文件包含了 Java 程序运行时的二进制信息,如数据类型、方法信息等。class 文件格式也是在不断演化的,其被称之为 java 二进制特性,与 java 语言源代码特性不同,Java 二进制特性的演进相对比较保守,通常多个 Java 版本会保持相同的 class 文件格式。只有在重大语言特性修改时,才会引入新的class文件格式。所以 Java 语言版本和 class 文件格式版本不完全对应。

我们配置时,就需要同时考虑 java 言源代码特性版本的配置和 java 二进制特性版本的配置

java 二进制特性版本的配置

与服务端不同的是,我们的应用是跑在用户的手机上,用户可能用了低版本的 Android ,那么其 jvm 环境也就是低版本了。所以我们需要将我们的代码编译成低版本 jvm 环境也能运行的字节码。

如果是 java, 那么可以通过 targetCompatibility 来配置:

kts 复制代码
compileOptions {
    targetCompatibility = JavaVersion.VERSION_11
} 

如果是 kotlin,则通过 jvmTarget 来配置

kts 复制代码
kotlinOptions {
    jvmTarget = "11"
}

现在我们设置目标为 java 11, 那么如果我们用户的手机系统低于 Android 10, 不支持 java 11,为何也能够正常工作呢?

这就要提到 desugaring 技术(google/desugar_jdk_libs)了,它可以将高版本的语法糖转换为低版本的实现,其实现是从字节码层面做转换。

那为什么我们不将目标版本设置得更低,而是要用 desugaring 技术呢?

因为这个 desugaring 技术可以通过 if/else 之类的手段判断 Android 版本,低版本才走 desugaring 转换后的实现,高版本保持使用高级特性,从而享受高级特性带来的性能提升。

那为什么要设置为 java 11 呢?

那是因为目前 desugar_jdk_libs 就只支持到了 java 11,所以目前主流的 Android 项目目前最高也只能设置到 java 11

Java 语言源代码特性版本的配置

我们回到 Android 的编译上,Android 使用 gradle 进行编译,而 gradle 也是跑在 java 环境的,它也是要求 java 环境的,例如最新的 8.x 系列是跑在 jdk 17 上,我们可以在 Android Studio > Setting > Build Tool > gradle 中配置。

由于 java 新版本总会出各种新的特性,所以我们不能用 jdk 17 去编译出 java 11 的字节码,即使编译得通,也容易出翔。在 gradle 旧版本,gradle 所运行的 jdk 环境与编译源码的 jdk 耦合比较严重,所以配置会出现相互影响与相互约束的情况。

gradle 7.4 出了 javaToolChain 的东西,它可以让我们配置编译源代码采用单独的 jdk

kts 复制代码
java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(11))
    }
}

如果使用了 kotlin,则配置:

kts 复制代码
kotlin {
    jvmToolchain(11)
}

当然,kotlin 要求版本至少为 1.5.30

Android 还可以设置 sourceCompatibility,其指明源码使用的 java 版本,有了 toolchain 后,它主要给 Android Studio 用,用于 lint 提示我们不要写出高版本的语法糖。

其实我们可以发现,toolchain 出来后,就可以把我们从 gradle 运行、java 源代码编译、kotlin 源代码编译采用 jdk 的严重耦合中解放出来,配置更灵活了,当然配置项也更多了,也有一定的理解成本,大家也需要明白各自的用途才能玩得很顺。

最后

gradle 虽然还是很慢,但是也不断有很多很好的改进点,早升级早享受。目前我们还可以将所有的配置项抽取出来,使用 Composing builds 管理,具体可以参考官方的 Now in Android 项目或者我的 emo 项目的 build-logic


我是古哥E下,前微信读书客户端程序猿 / 自学 5 年中医,维护过上万 Star 开源项目 QMUI Android,现独立维护好用简洁的 Android 组件库 emo

关注我可得:ChatGPT 开发玩法 | 程序员学习经验 | 组件库新变动 | 中医健康调理 。

emo官网:emo.qhplus.cn

相关推荐
HerayChen1 小时前
HbuildderX运行到手机或模拟器的Android App基座识别不到设备 mac
android·macos·智能手机
顾北川_野1 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
hairenjing11231 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
小黄人软件1 小时前
android浏览器源码 可输入地址或关键词搜索 android studio 2024 可开发可改地址
android·ide·android studio
dj15402252032 小时前
group_concat配置影响程序出bug
android·bug
周全全2 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
- 羊羊不超越 -3 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
wk灬丨3 小时前
Android Kotlin Flow 冷流 热流
android·kotlin·flow
千雅爸爸3 小时前
Android MVVM demo(使用DataBinding,LiveData,Fresco,RecyclerView,Room,ViewModel 完成)
android