本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。
1. VSCODE 插件
- Code Runner
- Extension Pack for Java
- Maven for Java
- Debugger for Java
- Test Runner for Java
- Project Manager for Java
- Language Support for Java(TM) by Red Hat
- Java Debugger
2. ubuntu20.04安装Java
默认的ubuntu20.04源仓库包含了两个openJDK软件包,Java Runtime Environment(JRE)和Java Development Kit(JDK)。JRE主要包含了Java虚拟机(JVM),类和允许你允许Java程序的二进制包。JDK包含JRE和用于构建Java应用的开发/调试工具和库文件.
Java11s java的一个长期支持版本,同时也是Ubuntu20.04的默认Java开发和运行环境。
3. java 编译
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 编译单个文件
javac test.java
javac test
# package
javac -d . *.java
java animals/MammalInt
javac -d ../ JNIDemo.java Java2Cplusplus.java BaseClass.java
javac test.java
java -Djava.library.path=./JNIDemo test
# JNI
javac -h . JNIDemo.java
javap -s -p Java2Cplusplus.class
# cpp
g++ -fPIC -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux/ -shared -o libcom_huhu_test_JNIDemo.so com_huhu_test_JNIDemo.cpp
|
4. JNI
4.1. JAVA调用C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import com.huhu.test.*;
/* 文件名 : MammalInt.java */
public class test
{
public static void main(String[] args)
{
//加载C文件
System.loadLibrary("com_huhu_test_JNIDemo");
JNIDemo jniDemo = new JNIDemo();
jniDemo.testHello();
int[] data = {1, 2, 3};
float[] f = jniDemo.execute(data, 1, 2, 3);
System.out.println(f[0]);
System.out.println(f[1]);
System.out.println(f[2]);
}
}
|
4.2. 生成 头文件 com_huhu_test_JNIDemo
1
|
javac -h . JNIDemo.java
|
JNIDemo.java :
1
2
3
4
5
6
7
8
|
package com.huhu.test;
public class JNIDemo
{
//定义一个方法,该方法在C中实现
public native void testHello();
public native float[] execute(int[] data, int width, int height, float ep);
}
|
com_huhu_test_JNIDemo.h :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_huhu_test_JNIDemo */
#ifndef _Included_com_huhu_test_JNIDemo
#define _Included_com_huhu_test_JNIDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_huhu_test_JNIDemo
* Method: testHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_huhu_test_JNIDemo_testHello
(JNIEnv *, jobject);
/*
* Class: com_huhu_test_JNIDemo
* Method: execute
* Signature: ([IIIF)[F
*/
JNIEXPORT jfloatArray JNICALL Java_com_huhu_test_JNIDemo_execute
(JNIEnv *, jobject, jintArray, jint, jint, jfloat);
#ifdef __cplusplus
}
#endif
#endif
|
4.3. 实现 com_huhu_test_JNIDemo
com_huhu_test_JNIDemo.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
// g++ -fPIC -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux/ -shared -o libTestJni.so
// TestJni.cpp
#include "com_huhu_test_JNIDemo.h"
#include <jni.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define JNI_JAVA2C_PATH "com/huhu/test/Java2Cplusplus"
#define JNI_BASE_CLASS_PATH "com/huhu/test/BaseClass"
JNIEXPORT void JNICALL Java_com_huhu_test_JNIDemo_testHello(JNIEnv *env, jobject thiz)
{
std::cout << "this is Java_com_huhu_test_JNIDemo_testHello C++ print" << std::endl;
}
JNIEXPORT jfloatArray JNICALL Java_com_huhu_test_JNIDemo_execute(JNIEnv *env, jobject thiz, jintArray data, jint width, jint height, jfloat ep)
{
std::cout << "this is Java_com_huhu_test_JNIDemo_execute C++ print" << std::endl;
unsigned char *data_src = (unsigned char *)env->GetIntArrayElements(data, NULL);
std::cout << "data_src " << data_src[0] << " " << data_src[1] << " " << data_src[2] << " " << std::endl;
std::cout << "width height ep " << width << " " << height << " " << ep << " " << std::endl;
std::vector<float> result{0.1, 0.2, 0.3};
jfloatArray resultArray = env->NewFloatArray(result.size());
env->SetFloatArrayRegion(resultArray, 0, result.size(), &result[0]);
/* ------------------ */
//步骤1:
jclass clazz = env->FindClass(JNI_JAVA2C_PATH);
//步骤2:<init>是java的构造函数名,这个有点特殊。在我的一篇文章jetpack中的问题中碰见过它。
//构造函数没输入输出参数,所以这里的signature填写为()V
jmethodID method_init_id = env->GetMethodID(clazz, "<init>", "()V");
jmethodID method_set_id = env->GetMethodID(clazz, "setNum", "(I)V");
jmethodID method_get_id = env->GetMethodID(clazz, "getNum", "()I");
jclass base = env->FindClass(JNI_BASE_CLASS_PATH);
jmethodID method_base_init_id = env->GetMethodID(base, "<init>", "()V");
jobject objbase = env->NewObject(base, method_base_init_id);
jmethodID method_get_jobject_id = env->GetMethodID(clazz, "getNum", "(Lcom/huhu/test/BaseClass;)I");
//步骤3:
//创建了 Java2Cplusplus 对象
jobject obj = env->NewObject(clazz, method_init_id);
//步骤4:调用相应的方法
env->CallVoidMethod(obj, method_set_id, 21); // set函数没返回值
int year = env->CallIntMethod(obj, method_get_id); // getYear有返回值
int year2 = env->CallIntMethod(obj, method_get_jobject_id,objbase); // getYear有返回值
std::cout << "year " << year << std::endl;
std::cout << "year2 " << year2 << std::endl;
/* ------------------ */
return resultArray;
}
|
4.4. 编译 com_huhu_test_JNIDemo.cpp
1
2
3
4
5
6
|
g++ -fPIC -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux/ -shared -o libcom_huhu_test_JNIDemo.so com_huhu_test_JNIDemo.cpp
g++ -fPIC -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux/ -shared -o libcom_huhu_test_UfcwStrategy.so com_huhu_test_UfcwStrategy.cpp
g++ -fPIC -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.11.0-openjdk-amd64/include/linux/ -shared -o libcom_ufcw_strategy_UfcwStrategy.so com_ufcw_strategy_UfcwStrategy.cpp
|
4.5. 编译运行 java
1
2
3
4
5
6
7
8
9
|
javac -d ../ JNIDemo.java Java2Cplusplus.java BaseClass.java
cd ../
javac test.java
java -Djava.library.path=./JNIDemo test
|
4.6. JNI GetFieldID和GetMethodID 所需签名参数
调用JNI的GetMethodID函数获取一个jmethodID时,需要传入一个方法名称和方法签名,方法名称就是在Java中定义的方法名,方法签名的格式为:(形参参数类型列表)返回值。
1.基本类型签名
Java |
Native |
Signature |
byte |
jbyte |
B |
char |
jchar |
C |
double |
jdouble |
D |
float |
jfloat |
F |
int |
jint |
I |
short |
jshort |
S |
long |
jlong |
J |
boolean |
jboolean |
Z |
void |
void |
V |
2.引用数据类型的转换.
Java |
Native |
Signature |
所有对象 |
jobject |
L+classname +; |
Class |
jclass |
Ljava/lang/Class; |
String |
jstring |
Ljava/lang/String; |
Throwable |
jthrowable |
Ljava/lang/Throwable; |
Object[] |
jobjectArray |
[L+classname +; |
byte[] |
jbyteArray |
[B |
char[] |
jcharArray |
[C |
double[] |
jdoubleArray |
[D |
float[] |
jfloatArray |
[F |
int[] |
jintArray |
[I |
short[] |
jshortArrsy |
[S |
long[] |
jlongArray |
[J |
boolean[] |
jbooleanArray |
[Z |
获取签名方式:
方法:int (int param);
签名:(I)I
1、使用javac,生成对应java文件的class文件;
2、使用 javap -s -p 命令获取对应签名信息,如图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Compiled from "Java2Cplusplus.java"
public class com.huhu.test.Java2Cplusplus {
private int num;
descriptor: I
public com.huhu.test.Java2Cplusplus();
descriptor: ()V
public void setNum(int);
descriptor: (I)V
public int getNum();
descriptor: ()I
public int getBaseClassNum(com.huhu.test.BaseClass);
descriptor: (Lcom/huhu/test/BaseClass;)I
}
|