0
点赞
收藏
分享

微信扫一扫

Java + lua

sunflower821 2023-09-18 阅读 139

我们写东西的时候总会遇到lua中要调用java代码,当然这个用JNI肯定是可以做到的,但是有更加方便的办法—LuaJavaBridge

一、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;
    }

-- Java 类的名称
local className = "com/qeeplay/frameworks/CheShi"
-- 调用 的Java 方法名
local method = 'getDisplayWidth'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 调用 Java 方法
local _, screenwidth = luaj.callStaticMethod(className, method, args)

三、luaj 实现原理

luaj 的核心目标有两个:从 Lua 调用 Java, 从 Java 调用 Lua。整理出来就是如下几点

* 查找并调用指定的 Java 方法
* 检查调用结果,并从 Java 方法获取返回值
* 将 Lua function 作为参数传递给 Java 方法
* 在 Java 方法中调用 Lua function

四、查找并调用指定的 Java 方法

JNI提供了 FindClass() 方法用于查找指定的 Class,所以 luaj.callStaticMethod() 的第一个参数就是要调用的 Java Class 的完整类名称(类名称中的“.”要替换为“/”)。

找到指定 Class 后,利用 JNI 的 GetStaticMethodID() 方法就可以找到这个类的指定静态方法,前提是要提供静态方法的名称和签名。

所谓签名,就是指Java方法的参数类型和返回类型定义。例如前面示例代码中 GameInterface_doBilling() 方法的签名是 (Ljava/lang/String;ZZI)V 分享一套 181G视频的Java架构师课程,累计更新时长1000+个小时关于 Java 方法签名的具体定义,可以参考:JNI Type Signatures。
这里要说的是 luaj 可以根据调用参数自动猜测方法签名所以示例中我们并没有写签名
示例中指定参数

注 意

 文末有:7701页互联网大厂面试题 

local args = {n}

luaj 根据这 个参数,会构造出正确的方法签名。

注意

这里要说的是 Lua 里没有办法准确判断一个数值是整数还是浮点数,所以 luaj 在猜测方法签名时,假定所有的数值都是浮点数。所以下面调用会报错

public static int getNum(int n) {
  return n;
}
-- Java 类的名称
local className = "com/qeeplay/frameworks/CheShi"
-- 调用 的Java 方法名
local method = 'getDisplayWidth'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 调用 Java 方法
local _, screenwidth = luaj.callStaticMethod(className, method, args)

这样是不行的,所以这个时候我们要自己定义签名

下面给出正确的示例

public static int getNum(int n) {
  return n;
}
-- Java 类的名称
local className = "com/qeeplay/frameworks/CheShi"
-- 调用 的Java 方法名
local method = 'getDisplayWidth'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 定义签名-- 参数: [I]nteger-- 返回值: [I]nt
local sig = "(I)I"
-- 调用 Java 方法
local _, screenwidth = 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 方法获取返回值

uaj调用 Java 方法时,可能会出现各种错误,因此 luaj 提供了一种机制让 Lua 调用代码可以确定 Java 方法是否成功调用。
luaj.callStaticMethod() 会返回两个值:

* 当成功时,第一个值为 true,第二个值是 Java 方法的返回值(如果有)。
* 当失败时,第一个值为 false,第二个值是错误代码。

下面的代码展示了如何检查返回结果和获得返回值:

java代码

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 引用表分享一套 181G视频的Java架构师课程,累计更新时长1000+个小时当一个 Lua function 传递给 Java 时,这个 function 对应的值会被存在引用表中,并获得一个唯一的引用 ID (整数)。Java 代码拿到这个引用 ID 后,就可以很方便的调用该 Lua function 了。

所以Java 方法里接收 Lua function 的参数必须定义为 int 类型
示例

public static int getNum(int n) {
  return n;
}
local function callback(result)
     ---方法内容
end
-- Java 类的名称
local className = "com/qeeplay/frameworks/CheShi"
-- 调用 的Java 方法名
local method = 'getDisplayWidth'
-- 调用 Java 方法需要的参数
local args = {
     callback
}
-- 定义签名-- 参数: [I]nteger-- 返回值: [I]nt
local sig = "(I)I"
-- 调用 Java 方法
local _, screenwidth = luaj.callStaticMethod(className, method, args,sig)

举报

相关推荐

0 条评论