首页 > 编程语言 >Java JNA、JNI、ProcessBuilder、Runtime.getRuntime.exec()详解

Java JNA、JNI、ProcessBuilder、Runtime.getRuntime.exec()详解

时间:2024-09-19 21:22:13浏览次数:12  
标签:Java ProcessBuilder exec int 代码 本地 JNI 交互


 Java 提供了几种方式与非 Java 代码进行交互(比如调用本地库或执行外部程序),其中包括 JNA、JNI、ProcessBuilderRuntime.getRuntime().exec()。下面是对每种方式的详细解释。


1. JNA (Java Native Access)

简介

JNA 是 Java 与本地代码进行交互的一种高层次 API,它允许 Java 程序调用本地动态链接库(DLL 或 .so 文件)中的函数,而无需编写 JNI(Java Native Interface)代码。JNA 大大简化了与本地代码的交互,因为它自动处理了参数的转换、调用约定等复杂细节。

使用场景

  • 需要调用现有的本地库(如 C/C++ 编写的 DLL 或 .so)。
  • 不需要手动编写复杂的 JNI 代码。
  • 性能要求没有 JNI 那么高。

工作原理

JNA 使用动态代理模式,将 Java 方法映射到本地库函数。它依赖于 com.sun.jna.Native 类来加载本地库,并通过接口定义与本地库中的函数进行交互。

示例代码

假设有一个名为 mydll.dll 的 C 函数:

// mydll.c
int add(int a, int b) {
    return a + b;
}

在 Java 中通过 JNA 调用它:

import com.sun.jna.Library;
import com.sun.jna.Native;

public class MyDllCaller {
    // 定义与DLL函数的接口
    public interface MyDll extends Library {
        MyDll INSTANCE = (MyDll) Native.load("mydll", MyDll.class);
        int add(int a, int b);
    }

    public static void main(String[] args) {
        int result = MyDll.INSTANCE.add(3, 4);
        System.out.println("Result: " + result);  // 输出 7
    }
}

优点

  • 简单易用,减少了手动处理本地库调用的复杂性。
  • 无需生成本地代码,直接通过接口与动态库交互。
  • 支持跨平台使用,动态加载库。

缺点

  • 性能相对比 JNI 稍低。
  • 不支持复杂的指针操作和本地数据结构的深度操作。

------------------------------------------------------------------------------------------------------------------------------

2. JNI (Java Native Interface)

简介

Java中传参并调用C++程序_java 调用c++ 传递参数-CSDN博客

JNI 是 Java 与本地代码(如 C/C++)交互的低层次接口。它允许 Java 直接调用 C/C++ 函数,或者将 C/C++ 代码嵌入到 Java 应用中。与 JNA 不同,JNI 需要编写本地代码,并且通过 JNI 的 API 来与 Java 进行交互。

使用场景

  • 对性能有严格要求,需要与本地代码进行高效交互。
  • 需要访问 Java 环境中的复杂数据结构,或需要在 C/C++ 中对 Java 对象进行操作。
  • 需要与不使用动态库的本地代码进行深度集成。

工作原理

  1. 编写 Java 代码声明本地方法。
  2. 使用 javah 生成 C/C++ 头文件。
  3. 编写与 Java 本地方法匹配的 C/C++ 实现。
  4. 使用 JNI API 与 JVM 进行交互。

示例代码

Java 代码:

public class MyJNI {
    // 声明本地方法
    public native int add(int a, int b);

    static {
        // 加载本地库
        System.loadLibrary("myjni");
    }

    public static void main(String[] args) {
        MyJNI jni = new MyJNI();
        int result = jni.add(3, 4);
        System.out.println("Result: " + result);  // 输出 7
    }
}

C/C++ 实现:

#include <jni.h>
#include "MyJNI.h"  // 生成的头文件

JNIEXPORT jint JNICALL Java_MyJNI_add(JNIEnv *env, jobject obj, jint a, jint b) {
    return a + b;
}

优点

  • 高性能,适合需要频繁调用本地代码的场景。
  • 灵活,可以访问和操作 Java 对象。
  • 完全控制,可以处理复杂的指针操作和数据结构。

缺点

  • 编写和维护 JNI 代码相对复杂,需要理解 JNI 的 API 以及 Java 和本地代码之间的内存管理。
  • 跨平台支持复杂,不同平台需要不同的本地库。
  • 调试难度大。

3. ProcessBuilder

简介

ProcessBuilder 是 Java 中用于创建和管理操作系统进程的类。它允许 Java 程序启动外部进程(如可执行文件、脚本等),并与该进程进行交互(如传递输入、读取输出、检查退出状态)。

使用场景

  • 需要从 Java 中运行外部程序(如 .exe 或脚本)。
  • 与外部工具或服务进行交互。
  • 对进程的启动、输入输出管理有较高的需求。

工作原理

ProcessBuilder 创建一个新的进程,并允许通过流(InputStream/OutputStream)与进程进行交互。

示例代码

import java.io.*;

public class ProcessBuilderExample {
    public static void main(String[] args) {
        try {
            // 使用 ProcessBuilder 运行命令
            ProcessBuilder builder = new ProcessBuilder("ping", "google.com");

            // 启动进程
            Process process = builder.start();

            // 读取进程的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待进程结束
            int exitCode = process.waitFor();
            System.out.println("Exit code: " + exitCode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优点

  • 提供了对进程的详细控制,包括重定向输入输出流。
  • 支持异步进程的管理(通过 Process.waitFor() 等方法)。
  • 简单易用,可以启动任何外部程序或脚本。

缺点

  • 对外部程序的依赖性强,外部程序的路径和可用性可能会有问题。
  • 进程之间的数据传输主要依赖于流,处理复杂的交互时可能会变得笨重。
  • 不适合高频调用外部程序的场景,启动进程的开销较大。

4. Runtime.getRuntime().exec()

简介

Runtime.getRuntime().exec()ProcessBuilder 的旧版本 API,也用于从 Java 程序中执行外部命令或程序。它可以启动外部进程并返回 Process 对象,用于与进程交互。

使用场景

  • 需要从 Java 中简单地运行一个外部命令或程序。
  • 不需要对进程有复杂的控制和管理要求。

工作原理

通过调用 Runtime.getRuntime() 获取当前 JVM 的运行时对象,然后调用其 exec() 方法启动外部进程。

示例代码

import java.io.*;

public class RuntimeExecExample {
    public static void main(String[] args) {
        try {
            // 执行外部命令
            Process process = Runtime.getRuntime().exec("ping google.com");

            // 读取输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待进程结束
            int exitCode = process.waitFor();
            System.out.println("Exit code: " + exitCode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优点

  • 简单直接,可以快速执行命令。
  • 支持与操作系统的简单交互。

缺点

  • 功能不如 ProcessBuilder 强大,无法对输入输出重定向和环境变量进行详细控制。
  • 对于复杂的进程管理需求不够灵活。

Java JNA、JNI、ProcessBuilder、Runtime.getRuntime.exec()详解_本地库

编辑

标签:Java,ProcessBuilder,exec,int,代码,本地,JNI,交互
From: https://blog.51cto.com/u_15157190/12059119

相关文章

  • JavaScript高级——对象创建模式
    1、Object构造函数模式①套路:先创建空Object对象,再动态添加属性/方法②使用场景:起始时不确定对象内部数据③问题:语句太多2、对象字面量模式①套路:使用{  } 创建对象,同时指定属性/方法②适用场景:起始时对象内部数据是确定的③问题:如果创建多个对象,有重......
  • Java线程内容
    一:线程的创建继承Thread类重写run方法publicclassMyTest{publicstaticvoidmain(String[]args){MyJobmj=newMyJob();mj.start();}}classMyJobextendsThread{@Overridepublicvoidrun(){for(inti=0;i......
  • 在Java中,有没有其他方式可以替代List<Map<String,Object>>来存储和处理数据?
    在Java中,有多种方式可以替代List<Map<String,Object>>来存储和处理数据。选择哪种方式取决于你的具体需求,比如数据结构的复杂性、类型安全、性能要求等。以下是一些常见的替代方案:自定义类(POJOs):创建一个或多个自定义类来表示数据。这种方式提供了类型安全,并且代码更易于理......
  • java学习9.19
    结合前端,在本地运行实现登陆操作。将在输入框的数据传给服务器,服务器再通过调用数据库的数据进行对比,实现简单的判断逻辑到这里的我就感觉内容多了起来,在之前连接数据库,数据库操作的时候,跟着教程走,只是知道简单的用法也能在之后自行配置这里的话数据库等操作变成了一个环节,还有......
  • Java开发环境搭建:JDK与Eclipse的完美组合
    摘要:本文简述了Java开发环境的搭建,包括JDK的安装、环境变量配置,以及EclipseIDE的设置。提供了详细的步骤指导,帮助Java初学者快速搭建开发环境并运行第一个项目。Java的跨平台特性与环境需求我们写C/C++时,直接下载VisualStudio,然后在里面直接写代码就可以了。但是Java不行。这不是......
  • Springboot基于JAVA技术的旅游信息交互系统6mj9s--程序+源码+数据库+调试部署+开发环
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容随着旅游业的蓬勃发展,游客对于旅游信息的获取与交互需求日益增长。为了提升旅游体验,促进旅游资源的有效整合与利用,本项目拟设计并实现一个基于JAVA......
  • Springboot基于Java对运动心跳数据分析系统设计与实现455j4(程序+源码+数据库+调试部署
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、研究背景与意义随着健康意识的提升,运动已成为现代人生活的重要组成部分。心跳数据作为反映人体健康状态的重要指标,在运动过程中尤为重要。然而......
  • 力扣42 接雨水 Java版本
    文章目录题目描述代码1题目描述给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。示例1:输入:height=[0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组[0,1,0,2,1,0,1,3,2,1,2,1]表示的高度图,在这种情况下,可以接......
  • centos789手动无脑用sh脚本安装Java8
    #老师给的文件是jdk1.8版本,所以我这边写的也是8的脚本输入命令:mkdir–p/export/data#放置相关的数据文件输入命令mkdir–p/export/servers#软件的安装目录输入命令:mkdir–p/export/software上传文件jdk-8u241-linux-x64.tar.gz到/export/software目录然后写一个安装......
  • java的二维数组
    二维数组的初始化 二维数组的进行for循环时的判断条件怎么确定的呢?  因为在二维数组是特殊的一维数组,c语言中二维数组首元素的代表的是地址,而首元素代表的是一组一维数组,计算首元素的长度也就是计算二维数组的行下标为0的一维数组的长度所以判断数组名的长度也就是判断......