ubuntu20.04 java 开发环境搭建及 JNI 使用

java开发环境搭建及JNI使用

本文采用知识共享署名 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™ 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开发和运行环境。

  • 安装

    sudo apt-get update
    sudo apt-get -y install openjdk-11-jdk
    java --version
    
  • 设置Java默认版本

    java  --version
    sudo update-alternatives --config java
    

    已经安装的Java版本都会输出,输入想要设置为默认的序列化,按enter即可

  • Java_HOME环境变量

    # 首先查看Java的安装位置
    update-alternatives --config java
    
    # 打开/etc/environment文件
    sudo vim /etc/environment
    # 将JAVA_HOME指定到OpenJDK11,在文件末尾添加
    JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64"
    
    # 运行下述命令让shell生效
    source /etc/environment
    
    # 验证JAVA_HOME环境变量
    echo $JAVA_HOME
    
  • vscode Java_HOME环境变量配置

    settings.json

    "java.jdt.ls.java.home": "/usr/lib/jvm/java-11-openjdk-amd64",
    

3. java 编译

# 编译单个文件
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++

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

javac -h . JNIDemo.java

JNIDemo.java

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 :

/* 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:

// 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

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.5. 编译运行 java


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.基本类型签名

JavaNativeSignature
bytejbyteB
charjcharC
doublejdoubleD
floatjfloatF
intjintI
shortjshortS
longjlongJ
booleanjbooleanZ
voidvoidV

2.引用数据类型的转换.

JavaNativeSignature
所有对象jobjectL+classname +;
ClassjclassLjava/lang/Class;
StringjstringLjava/lang/String;
ThrowablejthrowableLjava/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 命令获取对应签名信息,如图:

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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

002237

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值