在当前的 Android 开发生态中:

- Java 仍然是主流和官方推荐的应用层开发语言,绝大多数 Android App 的 UI、业务逻辑、网络请求等都是用 Java (或其近亲 Kotlin) 编写的。
- C/C++ 主要用于“性能优化”和“硬件交互”,当 Java 代码在处理某些任务(如游戏物理引擎、视频/音频编解码、图像处理、科学计算)感到吃力时,或者需要直接操作硬件(如通过蓝牙、USB 与外设通信)时,就会引入 C/C++。
- 它们通过 Java Native Interface (JNI) 机制桥接,这是 Java 代码调用 C/C++ 代码,以及 C/C++ 回调 Java 代码的唯一官方标准方式。
Java 在 Android 开发中的角色
Java 是 Android 平台的“一等公民”,也是过去十多年来的绝对主力。
Java 的主要用途:
- 应用层开发:编写 App 的所有可见和不可见逻辑。
- UI 布局与交互:通过 XML 布局文件和 Java/Kotlin 代码创建用户界面,响应用户点击、滑动等操作。
- 业务逻辑:实现 App 的核心功能,比如用户登录、数据展示、订单处理等。
- 网络通信:使用
HttpURLConnection,OkHttp,Retrofit等库进行网络请求和数据解析。 - 数据存储:使用
SharedPreferences,SQLite,Room等进行本地数据持久化。 - 依赖注入与架构:使用
Dagger,Hilt,MVVM,MVP等现代架构模式组织代码。
Java 的优势:
- 跨平台:“一次编写,到处运行”,Java 代码在 Android 设备上通过 Dalvik/ART 虚拟机执行,无需为不同硬件重新编译。
- 开发效率高:拥有极其丰富的第三方库(生态系统成熟),开发工具链(Android Studio, Gradle)非常完善。
- 内存管理自动:拥有自动垃圾回收机制,开发者无需手动管理内存,大大减少了内存泄漏和悬垂指针的风险。
- 类型安全:静态类型语言,在编译阶段就能发现很多错误。
Java 的劣势(也是引入 C/C++ 的原因):
- 性能开销:运行在虚拟机上,执行效率低于原生代码。
- 无法直接操作硬件:出于安全考虑,Java 代码无法直接访问内存地址或硬件寄存器。
- 在某些计算密集型任务上表现不佳:例如复杂的 3D 渲染、实时音视频处理等。
C/C++ 在 Android 开发中的角色
C/C++ 并不用于编写整个 App,而是作为“性能增强模块”或“硬件抽象层”被引入。
C/C++ 的主要用途:
- 游戏开发:
- 游戏引擎:像 Unity 和 Unreal Engine 的核心就是用 C++ 编写的,它们负责渲染、物理模拟等。
- 物理引擎:计算碰撞、力、运动等,需要极高的性能。
- 音视频处理:
- 编解码:对视频进行 H.264/H.265 的编码和解码,对音频进行 AAC/MP3 的编解码,这些算法复杂,计算量大,用 C/C++ 实现效率极高。
- 图像处理与计算机视觉:
- 滤镜、特效:对图片进行像素级的处理,如美颜、模糊、锐化等。
- 人脸识别、物体检测:调用 OpenCV 等库,它们的核心算法是用 C++ 实现的。
- 科学计算与模拟:
在金融、医疗、工程等领域进行复杂的数值计算。
- 硬件交互:
- 驱动程序:为特定的硬件(如指纹传感器、专用通信芯片)编写驱动程序。
- 通信协议:实现与外设(如通过蓝牙连接的打印机、医疗设备)的底层通信协议。
C/C++ 的优势:
- 极致性能:编译为本地机器码,直接在 CPU 上运行,没有虚拟机开销,执行速度极快。
- 内存控制力强:可以精细地控制内存的分配和释放,适合对内存和性能有极致要求的场景。
- 直接操作硬件:可以访问内存地址、寄存器,与硬件直接通信。
- 代码可复用:一个 C/C++ 库可以被 Android、iOS、桌面应用等多个平台复用。
C/C++ 的劣势:
- 开发复杂:手动管理内存,容易产生内存泄漏、悬垂指针等严重问题。
- 跨平台性差:代码需要为不同平台(ARM, x86)和不同架构进行编译。
- 缺乏丰富的现成库:相比于 Java,生态系统稍弱,很多功能需要自己从零实现。
- 调试困难:调试原生代码比调试 Java 代码要复杂得多。
如何结合使用:Java Native Interface (JNI)
JNI 是一座桥梁,它连接了 Java 世界和 C/C++ 世界。

工作流程:
-
在 Java 代码中声明一个
native方法: 这个方法没有具体的实现(没有 ),只是一个声明,告诉虚拟机这个方法的实现在本地(Native)代码中。// MyLibrary.java public class MyLibrary { // 声明一个 native 方法 public native String getStringFromNative(); // 加载包含 C/C++ 实现的库文件 static { System.loadLibrary("mylibrary"); // 加载 libmylibrary.so } } -
使用工具生成 C/C++ 的“存根”代码: 使用 Android Studio 自带的工具或
javah命令,根据 Java 类的native方法声明,生成一个对应的 C/C++ 头文件(.h),这个头文件定义了 Java 和 C/C++ 之间函数的签名。 -
在 C/C++ 中实现这个方法: 在生成的头文件基础上,编写 C/C++ 代码来实现
getStringFromNative的功能,实现时需要遵循 JNI 规则来处理数据类型转换(Java 的String对应 C 的jstring)。// mylibrary.c #include <jni.h> #include <string.h> #include "MyLibrary.h" // 生成的头文件 // JNIEXPORT 和 JNICALL 是宏,用于声明导出函数 //JNIEXPORT JNICALL jstring JNICALL Java_MyLibrary_getStringFromNative(JNIEnv *env, jobject thiz) { // return (*env)->NewStringUTF(env, "Hello from C/C++!"); //} // 注意:函数名有严格的命名规则:Java_包名_类名_方法名 JNIEXPORT jstring JNICALL Java_com_example_myapp_MyLibrary_getStringFromNative(JNIEnv *env, jobject thiz) { // 创建一个 Java 字符串并返回 return (*env)->NewStringUTF(env, "Hello from C/C++!"); } -
编译 C/C++ 代码为共享库(
.so文件): 使用 Android NDK (Native Development Kit) 工具链将 C/C++ 源代码编译成平台相关的共享库文件(如libmylibrary.so),这个库文件会被打包进 APK 中。
(图片来源网络,侵删) -
在 Java 代码中调用: App 运行时,当调用
MyLibrary.getStringFromNative()时,Android 运行时会找到并加载libmylibrary.so,然后执行其中的 C/C++ 代码,并将结果返回给 Java。
数据传递与回调:
- Java -> C/C++:基本数据类型可以直接传递,对象和数组需要通过 JNI 提供的 API 进行转换。
- C/C++ -> Java:C/C++ 代码可以通过 JNIEnv 指针访问 Java 对象的方法和字段,从而实现回调,C/C++ 计算完一个结果后,可以调用一个 Java 的回调方法将结果传回。
现代趋势:Kotlin 与 C/C++
Google 官方推荐使用 Kotlin 作为 Android 的主要开发语言,而不是 Java,C/C++ 与 Java 的结合方式完全适用于 Kotlin。
- Kotlin 调用 C/C++:流程和 Java 几乎完全一样,Kotlin 同样支持
external关键字来声明native方法,并且与 JNI 的兼容性非常好。 - C++ 作为 Kotlin 的扩展:由于 Kotlin 可以作为脚本语言(Kotlin Script)和更灵活的编程语言,一些开发者正在探索用 C++ 来扩展 Kotlin 的能力,尤其是在性能敏感的领域。
总结与对比
| 特性 | Java (应用层) | C/C++ (原生层) |
|---|---|---|
| 主要角色 | App 的主体:UI、业务逻辑、网络 | 性能增强模块:计算密集、硬件交互 |
| 性能 | 较好(有虚拟机开销) | 极高(编译为机器码) |
| 内存管理 | 自动垃圾回收 | 手动管理(易出错) |
| 开发效率 | 高(库丰富,工具链完善) | 较低(复杂,调试困难) |
| 跨平台 | 好(一次编译,多设备运行) | 差(需为不同架构编译) |
| 硬件交互 | 不能(安全限制) | 可以(直接访问) |
| 调试难度 | 较低 | 高 |
| 结合方式 | 通过 JNI 调用 C/C++ | 作为被 Java/Kotlin 调用的库 |
一句话总结:
用 Java/Kotlin 构建你的 App 的“骨架”和“血肉”(UI 和业务逻辑),当遇到 Java/Kotlin 处理不了的“硬骨头”(性能瓶颈或硬件需求)时,就用 C/C++ 来啃,并通过 JNI 这座桥梁把它们连接起来。
