當前位置: 妍妍網 > 碼農

Java與lua互相呼叫簡單教程

2024-04-28碼農

來源:網路

👉 歡迎 ,你將獲得: 專屬的計畫實戰 / Java 學習路線 / 一對一提問 / 學習打卡 / 贈書福利

全棧前後端分離部落格計畫 2.0 版本完結啦, 演示連結 http://116.62.199.48/ 新計畫正在醞釀中 。全程手摸手,後端 + 前端全棧開發,從 0 到 1 講解每個功能點開發步驟,1v1 答疑,直到計畫上線。 目前已更新了239小節,累計38w+字,講解圖:1645張,還在持續爆肝中.. 後續還會上新更多計畫,目標是將Java領域典型的計畫都整一波,如秒殺系統, 線上商城, IM即時通訊,Spring Cloud Alibaba 等等,

  • luaj 主要特征

  • luaj 用法範例

  • luaj 實作原理

  • 尋找並呼叫指定的 Java 方法

  • 從 Java 方法獲取返回值

  • 將 Lua function 作為參數傳遞給 Java 方法

  • 在某些業務場景下,我們可能會遇到 lua 中要呼叫 java 程式碼情況,當然這個用 JNI 肯定是可以做到的,但是有更加方便的辦法:LuaJavaBridge(LuaJava)和 LuaJ。

    luaj 主要特征

  • 可以從 Lua 呼叫 Java class Static Method

  • 呼叫 Java 方法時,支持 int/float/boolean/String/Lua function 五種參數型別

  • 可以將 Lua function 作為參數傳遞給 Java,並讓 Java 保存 Lua function 的參照

  • 可以從 Java 呼叫 Lua 的全域函式,或者呼叫參照指向的 Lua function

  • luaj 的功能很簡單,但對於整合各種 SDK 來說已經完全滿足需求了。

    luaj 用法範例

    Java 方法原型:

    public static float getNum(float n) {
    return n;
    }

    lua 呼叫範例:

    -- Java 類的名稱
    local className = "com/xttblog/Test"
    -- 呼叫 的Java 方法名
    local method = 'getNum'
    -- 呼叫 Java 方法需要的參數
    local n = 10
    local args = {
    n
    }
    -- 呼叫 Java 方法
    local _, testStaticMethod = luaj.callStaticMethod( className, method, args)

    luaj 實作原理

    luaj 的核心目標有兩個:從 Lua 呼叫 Java, 從 Java 呼叫 Lua。整理出來就是如下幾點

  • 尋找並呼叫指定的 Java 方法

  • 檢查呼叫結果,並從 Java 方法獲取返回值

  • 將 Lua function 作為參數傳遞給 Java 方法

  • 在 Java 方法中呼叫 Lua function

  • 尋找並呼叫指定的 Java 方法

    JNI 提供了 Find class() 方法用於尋找指定的 class,所以 luaj.callStaticMethod() 的第一個參數就是要呼叫的 Java class 的完整類名稱(類名稱中的「.」要替換為「/」)

    找到指定 class 後,利用 JNI 的 GetStaticMethodID() 方法就可以找到這個類的指定靜態方法,前提是要提供靜態方法的名稱和簽名。

    所謂簽名,就是指Java方法的參數型別和返回型別定義。方法的簽名就是類似 (Ljava/lang/String;ZZI)V 這樣的一串描述,透過字節碼方式可以檢視,如下範例:

    圖片

    關於 Java 方法簽名的具體定義,可以參考: JNI Type Signatures

    這裏要說的是 luaj 可以根據呼叫參數自動猜測方法簽名所以範例中我們並沒有寫簽名。

    範例中指定參數:

    local args = {n}

    luaj 根據這 個參數,會構造出正確的方法簽名。

    註意:這裏要說的是 Lua 裏沒有辦法準確判斷一個數值是整數還是浮點數,所以 luaj 在猜測方法簽名時,假定所有的數值都是浮點數。所以下面呼叫會報錯:

    public static int getNum(int n) {
    return n;
    }
    -- Java 類的名稱
    local className = "com/xttblog/Test"
    -- 呼叫 的Java 方法名
    local method = 'getNum'
    -- 呼叫 Java 方法需要的參數
    local n = 10
    local args = {
    n
    }
    -- 呼叫 Java 方法
    local _, testStaticMethod = luaj.callStaticMethod( className, method, args)

    這樣是不行的,所以這個時候我們要自己定義簽名。

    下面給出正確的範例

    public static int getNum(int n) {
    return n;
    }
    -- Java 類的名稱
    local className = "com/xttblog/Test"
    -- 呼叫 的Java 方法名
    local method = 'getNum'
    -- 呼叫 Java 方法需要的參數
    local n = 10
    local args = {
    n
    }
    -- 定義簽名-- 參數: [I]nteger-- 返回值: [I]nt
    local sig = "(I)I"
    -- 呼叫 Java 方法
    local _, testStaticMethod = luaj.callStaticMethod( className, method, args,sig)

    簽名使用「(依次排列的參數型別)返回值型別」的格式,幾個例子如下:

    簽名 解釋
    ()V 參數:無,返回值:無
    (I)V 參數:int,返回值:無
    (Ljava/lang/String;)Z 參數:字串,返回值:布爾值
    (IF)Ljava/lang/String; 參數:整數、浮點數,返回值:字串

    這裏列出不同型別對應的 Java 簽名字串:

    型別名 型別
    I 整數,或者 Lua function
    F 浮點數
    Z 布爾值
    Ljava/lang/String; 字串
    V Void 空,僅用於指定一個 Java 方法不返回任何值

    Java 方法裏接收 Lua function 的參數必須定義為 int 型別

    從 Java 方法獲取返回值

    luaj 會檢查呼叫結果,並從 Java 方法獲取返回值。

    luaj 呼叫 Java 方法時,可能會出現各種錯誤,因此 luaj 提供了一種機制讓 Lua 呼叫程式碼可以確定 Java 方法是否成功呼叫。

    luaj.callStaticMethod() 會返回兩個值:

  • 當成功時,第一個值為 true,第二個值是 Java 方法的返回值(如果有)。

  • 當失敗時,第一個值為 false,第二個值是錯誤程式碼。

  • 下面的程式碼展示了如何檢查返回結果和獲得返回值:

    public static int AddTwoNumbers(final int number1, final int number2) {
    return number1 + number2;
    }

    Lua程式碼

    local args = {2, 3}
    local sig = "(II)I"
    local ok, ret = luaj.callStaticMethod( className, "AddTwoNumbers", args, sig)
    if not ok then
    print("luaj error:", ret)
    else
    print("ret:", ret) -- 輸出 ret: 5
    end

    錯誤程式碼定義如下:

    錯誤程式碼 描述
    -1 不支持的參數型別或返回值型別
    -2 無效的簽名
    -3 沒有找到指定的方法
    -4 Java 方法執行時丟擲了異常
    -5 Java 虛擬機器出錯
    -6 Java 虛擬機器出錯

    將 Lua function 作為參數傳遞給 Java 方法

    Lua 虛擬機器中,Lua function 以值的形式保存。但這個值無法直接給 Java 用,所以 luaj 做了一個 Lua function 參照表。當一個 Lua function 傳遞給 Java 時,這個 function 對應的值會被存在參照表中,並獲得一個唯一的參照 ID (整數)。Java 程式碼拿到這個參照 ID 後,就可以很方便的呼叫該 Lua function 了。

    所以 Java 方法裏接收 Lua function 的參數必須定義為 int 型別。

    範例:

    public static int getNum(int n) {
    return n;
    }
    localfunction callback(result)
    ---方法內容
    end
    -- Java 類的名稱
    local className = "com/xttblog/Test"
    -- 呼叫 的Java 方法名
    local method = 'getNum'
    -- 呼叫 Java 方法需要的參數
    local args = {
    callback
    }
    -- 定義簽名-- 參數: [I]nteger-- 返回值: [I]nt
    local sig = "(I)I"
    -- 呼叫 Java 方法
    local _, testStaticMethod = luaj.callStaticMethod( className, method, args,sig)

    另外,LuaJ 也很好用。只需引入 pom。


    ‍然後直接把 lua 程式碼當做 String 字串內嵌到 Java 程式碼中:

    String luaStr = "print 'hello,world!'";
    Globals globals = JsePlatform.standardGlobals();
    LuaValue chunk = globals.load(luaStr);
    chunk.call();

    也可以建立一個 login.lua 指令碼,內容如下:

    --無參函式
    function hello()
    print'hello'
    end
    --帶參函式
    functiontest(str)
    print('data from java is:'..str)
    return'haha'
    end

    然後,Java先載入login.lua指令碼並編譯,然後再獲取指定名稱的函式,無參的直接使用call()方法呼叫,帶參的需要透過invoke(LuaValue[])傳入參數列:

    String luaPath = "res/lua/login.lua"; //lua指令碼檔所在路徑
    Globals globals = JsePlatform.standardGlobals();
    //載入指令碼檔login.lua,並編譯
    globals.loadfile(luaPath).call();
    //獲取無參函式hello
    LuaValue func = globals.get(LuaValue.valueOf("hello"));
    //執行hello方法
    func.call();
    //獲取帶參函式test
    LuaValue func1 = globals.get(LuaValue.valueOf("test"));
    //執行test方法,傳入String型別的參數參數
    String data = func1.call(LuaValue.valueOf("I'am from Java!")).toString();
    //打印lua函式回傳的數據
    Logger.info("data return from lua is:"+data);

    執行結果如下:

    hello
    data from java is:I'am from Java!
    八月 07, 2022 5:31:25 下午 com.tw.login.tools.Logger info
    資訊: lua return data:haha

    👉 歡迎 ,你將獲得: 專屬的計畫實戰 / Java 學習路線 / 一對一提問 / 學習打卡 / 贈書福利

    全棧前後端分離部落格計畫 2.0 版本完結啦, 演示連結 http://116.62.199.48/ 新計畫正在醞釀中 。全程手摸手,後端 + 前端全棧開發,從 0 到 1 講解每個功能點開發步驟,1v1 答疑,直到計畫上線。 目前已更新了239小節,累計38w+字,講解圖:1645張,還在持續爆肝中.. 後續還會上新更多計畫,目標是將Java領域典型的計畫都整一波,如秒殺系統, 線上商城, IM即時通訊,Spring Cloud Alibaba 等等,


    1. 

    2. 

    3. 

    4. 

    最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java並行、SSM、微服務、資料庫、數據結構等等。

    獲取方式:點「在看」,關註公眾號並回復 Java 領取,更多內容陸續奉上。

    PS:因公眾號平台更改了推播規則,如果不想錯過內容,記得讀完點一下在看,加個星標,這樣每次新文章推播才會第一時間出現在你的訂閱列表裏。

    「在看」支持小哈呀,謝謝啦