声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635

目的:通过形参在Java 和C之间传递数据,尤其是大块的媒体数据
优点:避免通过返回值返回一个巨大的数据块
声明:下文的大量操作作者是为了在一个目录下完成全部动作适配的,你大可以有更好的做法。文中涉及的目录参考者根据自己需要修改。重点是介绍一个完整可用的例子。
Step1:Java源码:

package com.testjni;
public class TestJNI
{
    public native void tranferBytes(byte[] dataFromNative);
    static
    {
        // 装入动态链接库     
        System.load("D:\\eclipseWebWorkSpace\\testest\\src\\com\\testjni\\libTestJNI_amd64.dll"); 
    }
    public static void main(String[] args)
    {
        TestJNI testJNI = new TestJNI();
        // byte[] dataFromNative既是java传递给本地方法的参数,也是希望本地方法修改的参数
        byte[] dataFromNative = new byte[10];
        System.out.println("before-->dataFromNative=" + dataFromNative);
        for (int i = 0; i < 10; i++)
        {
            System.out.print(dataFromNative[i] + " ");
        }
        System.out.println("\n----------");
        testJNI.tranferBytes(dataFromNative);
        System.out.println("after-->dataFromNative=" + dataFromNative);
        for (int i = 0; i < 10; i++)
        {
            System.out.print(dataFromNative[i] + " ");
        }
    }
}

Step2:生成java类
javah -classpath D:\eclipseWebWorkSpace\testest\src com.testjni.TestJNI
Step3:生成jni头文件
javah -classpath D:\eclipseWebWorkSpace\testest\src com.testjni.TestJNI
生成的头文件如下。注意extern “C” {这个不能删除,否则C++的Name Mangling起作用运行时就无法找到自己写的函数了。

/* DO NOT EDIT THIS FILE - it is machine generated */
/*为了编译方便,把原本生成的#include <jni.h>改成了#include "jni.h"*/
#include "jni.h
/* Header for class com_testjni_TestJNI */
#ifndef _Included_com_testjni_TestJNI
#define _Included_com_testjni_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_testjni_TestJNI
 * Method:    tranferBytes
 * Signature: ([B)V
 */
JNIEXPORT void JNICALL Java_com_testjni_TestJNI_tranferBytes
  (JNIEnv *, jobject, jbyteArray);
#ifdef __cplusplus
}
#endif
#endif

Step4:编写C++源文件

#include "com_testjni_TestJNI.h" 
JNIEXPORT void JNICALL Java_com_testjni_TestJNI_tranferBytes(JNIEnv *jniEnv, jobject obj, jbyteArray dataFromNative)
{
    jbyte* p = jniEnv->GetByteArrayElements(dataFromNative, NULL);
    //这个地方就可以根据业务需要修改java传入的形参的值
    for (int i = 0; i < 10; i++)
    {
        p[i] = i;
    }
    jniEnv->ReleaseByteArrayElements(dataFromNative, p, 0);
    return; 
}

此时你的目录大概长这个样子
这里写图片描述
很遗憾,此时执行
cl/LD D:\eclipseWebWorkSpace\testest\src\com\testjni\com_testjni_TestJNI.cpp -o D:\eclipseWebWorkSpace\testest\src\com\testjni\libTestJNI_amd64.dll
是编译不过的,你还需要以下2个头文件的支持:
C:\Program Files\Java\jdk1.8.0_144\include\jni.h和
C:\Program Files\Java\jdk1.8.0_144\include\win32\jni_md.h
Step5:把这2个头文件拷贝到当前目录D:\eclipseWebWorkSpace\testest\src\com\testjni
Step6:如果jdk是64位的,需要打开Visual Studio x64 Cross Tools Command Prompt而不是那个32位的。
然后执行cl /LD D:\eclipseWebWorkSpace\testest\src\com\testjni\com_testjni_TestJNI.cpp -o D:\eclipseWebWorkSpace\testest\src\com\testjni\libTestJNI_amd64.dll
好,现在你的目录大概长这样
这里写图片描述
当然了,以上除了libTestJNI_amd64.dll外,其他2个都是副产品,不是必须的,可以删除了。
此时再去跑跑java 代码,输出
before–>dataFromNative=[B@15db9742
0 0 0 0 0 0 0 0 0 0


after–>dataFromNative=[B@15db9742
0 1 2 3 4 5 6 7 8 9