1. 程式人生 > 其它 >Java中一個逐漸被遺忘的強大功能,強到你難以置信!!

Java中一個逐漸被遺忘的強大功能,強到你難以置信!!

大家好,我是冰河~~

說起Java,簡單好用,但是Java中很多牛逼的技術卻逐漸被遺忘了~~

在Java語言出現之前,很多系統都是使用C和C++開發的。Java出現之後,由於其面向物件的思想更加符合人們的思維習慣,Java也不用像C和C++那樣需要程式設計師手動管理記憶體的分配和回收。說白了,就是簡單好用。由於Java的諸多優點,使其一躍霸榜程式語言前排很多年。

為了能夠和使用C和C++寫的程式進行互動,Java提供了本地方法的特性,也就是我們常說的JNI技術,然而,隨著網際網路的高速發展,分散式、微服務、大資料、雲端計算等技術和框架層出不窮,但大多數框架採用單一的語言所開發。JNI這項Java中提供的強大功能,卻逐漸的被人遺忘了。

為何使用JNI

最近,冰河在分析500多TB的資料,從500多TB的資料中分析使用者的行為習慣,以便為使用者提供更好的產品體驗和推薦更加適合使用者的產品。然而,在實現演算法的過程中,使用Java語言開發的演算法從500多TB的資料中,單獨分析某個使用者某段時間的行為時,耗費了極大的時間開銷。無論我如何優化演算法,都不能達到預期的效果。很顯然,這不符合效能要求。

一名小夥伴對我說:試試C語言嘛。對啊!我為啥不試試用C語言寫演算法啊,於是乎,使用C語言寫了演算法,經過不斷的優化和調整,算是初步達到了演算法效能要求。但是向資料大屏展示資料的時候,後端還是要以微服務的形式部署,於是我想到了Java中的JNI技術

注:後面單獨寫一篇我是如何分析500多TB資料的。

如何使用JNI

先說說使用JNI時有哪些坑吧,以避免小夥伴們重複踩坑,這裡,大家需要注意的是:在使用JNI技術呼叫dll動態連結庫時,32位dll只能是32位JDK去呼叫,64位dll只能是64位JDK去呼叫。這個必須是這樣的,如果發現無法呼叫或者提示版本錯誤,首先要檢查下JDK的位數和dll的位數是否是對應的。

為了能夠讓小夥伴們順利的按照文章開發出自己的JNI程式,這裡,我就詳細的說下如何開發一個JNI程式,主要分三個大的方面來說明如何使用JNI技術呼叫C和C++寫的程式。

注意:本文中我使用的是jna Java類庫實現JNI開發。

開發dll動態連結庫

下載VS

小夥伴們可以在【冰河技術】公眾號回覆“vscode”,獲取VS2010下載連結。

使用VS開發dll

VS新建專案

輸入專案名稱

選擇空專案,點選完成

建立完成後,將下面這段程式碼複製進去:

#include <windows.h> 
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl; 
 
#define MYLIBAPI extern "C" __declspec( dllexport ) 
 
//這的引數是必須的,也可以定義為.c標頭檔案
MYLIBAPI double add(double a,double b);
MYLIBAPI double mul(double a,double b);
MYLIBAPI char * getString(char* a);
 
double add(double a,double b){  
    return a + b;  
}
 
double mul(double a,double b){
	return a*b;
}
//定義了一個返回java String型別的引數
char * getString(char* a){
	char* b ="this is test";
	return strcat(a,b);
}

這裡要注意的是:java的String和cpp的String不一樣的,其對應的是char*,如果要用cpp的string不是亂碼就是呼叫失敗。

使用VS生成dll

這裡變成Release,點選配置管理器配置x64版本,這樣生成的dll就是x64版本的,這點非常重要。

配置完成以後右擊專案點選生成按鈕。

這一頓操作下來,基本就能夠正確的生成dll了,如果不能生成,極有可能是你的姿勢不對,照著文章重新弄一遍,如果還是不行,你就加我微信問我吧。

VS生成的dll檔案在哪個位置呢?別急,我們繼續。

右擊專案

這裡要注意的是在上級目錄!不要想當然開啟的專案位置然後直接就去x64去找了,根本沒用!裡面沒有dll,是在上級目錄,上級目錄 的x64位置。

開發Java程式

匯入Maven依賴

新建Maven專案後,在Maven的pom檔案中引入如下依賴。

<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform -->
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.3.1</version>
</dependency>

指定dll位置

我個人就放在這個lib包下面,這樣匯入這個包的時候可以寫絕對路徑也可以寫相對路徑。

編寫程式碼

注意:這裡定義的介面方法名稱需要和dll中的方法名稱一致。

package com.binghe.jni;
 
import com.sun.jna.Library;
import com.sun.jna.Native;
 
/**
 * @author binghe
 * @description: 測試JNI程式
 */
public class JnaTest {
    public interface TestProject extends Library {
        TestProject INSTANCE = (TestProject) Native.load("src/main/lib/testDll.dll",
                JnaTest.TestProject.class);
        public double add(double i, double j);
        public double mul(double i, double j);
        public String getString(String a);
 
    }
 
    public static void main(String[] args) {
 
        System.out.println(TestProject.INSTANCE.add(20.11,20.0));
        System.out.println(TestProject.INSTANCE.mul(16.9,20.89));
        System.out.println(TestProject.INSTANCE.getString("我現在正在測試dllgihjb"));
    }
}

執行Java程式

直接執行main方法,得到如下輸出結果。

大功告成~~

好了,今天就到這兒吧,我是冰河,我們下期見~~