项目背景
这里因为我没有具体项目需求只是单纯的闲 所以并没有写很多函数(lua)
lua和Java互相调用在网上也是少之又少 去看了几篇文章也是一头雾水可以说完全没看懂
我在Java的maven仓库中找到了一个名叫luaj-jse的库看上去挺靠谱的但是也没人教就很无奈 经过我呕心沥血的看源码终于弄懂了怎么写 这个库中的坑真嘎嘎多我在看的时候差点没骂几句脏话
那么废话不多说 今天带各位避避雷也顺便说一下luaj的开发思路 (这里多说一句gg的加库可能也是这个方法但我没看懂gg的源码 如果想学gg加库或许有帮助)
源码在文末
依赖
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-jse</artifactId>
<version>3.0.1</version>
</dependency>
这是一个spring项目的依赖 当然去直接下jar包也可以只是我懒得下
常用的对象介绍
LuaValue
这个对象是整个luaj-jse的超类他虽然继承至Varargs但是这个对象其实没什么用 用的最多的还是LuaValue
LuaTable
了解lua的看到这个类名应该也猜出来了 这个对象所做的其实就是创建一个lua数组(表)因为lua中的数组和Java不一样他可以是map的格式也就是键值对所以使用传统的方式创建lua的数组显然是不太合适 这里顺便提一嘴LuaValue对象你将他设置为数组也是可以当作lua的数组的 只不过不能使用键值对这个下面会介绍
LuaFunction
如果看懂了LuaTable对象的介绍那这个也肯定一看就懂 具体留到下面介绍
将Java对象转换为lua对象
使用CoerceJavaToLua.coerce(Object)即可将Java对象转换成lua的对象
直接上代码
lua.set("object",CoerceJavaToLua.coerce(myExtend));
myExtend
@Component
public class MyExtend {
/**
* 平平无奇的打印方法
* 在Luaj中
* Java对象里的方法可以明确写参数lua传递的参数会自动进去
* 但请注意参数类型 因为Java并不同lua他是强类型语言
* @param text 打印的内容
*/
public void print(String text) {
System.out.println(text);
}
public Map<String, Objects> newMap() {
return new HashMap<>();
}
}
demo.lua
--例子:调用LuaJava表中的对象
object:print("demo")
--例子:调用LuaJava表中的对象(Java jdk原生对象)
object:newMap()--创建一个mao对象
项目代码
主要是这些对象怎么使用 其实他们还是很好理解的 看到名字基本都能猜出来那么我们一个一个来介绍
LuaValue使用
这个对象中的方法非常多 但是有很多坑 这里挑几个常用并且使用的方法
首先是创建对象
创建对象不是直接new的不然得不到lua的全局环境如果想做的是lua与Java互相调用里创建lua全局环境我们后续将一些变量添加进lua的全局变量中
//创建lua全局环境
LuaValue lua=JsePlatform.standardGlobals();
这里是添加变量的例子 不需要进行类型转换luaj给我们提供的不同的方法可以自动帮我们转为lua中的类型
lua.set("name","白");//向lua全局环境中添加一个名为name的变量 而这个变量的值是白
lua.set("age",18);//同理
LuaTable使用
创建出来的结果类似于lua中的
{
name="白",
qq=3224886279
}
//创建lua中的一级数组
LuaTable arrLua=new LuaTable();
arrLua.set("name","白");//在数组中创建名为name的key 而他的value为白
arrLua.set("qq",3224886279L);//同理
需要注意的是这里创建一个数组仅仅只是一个数组 并不会在lua环境中也没有对应的lua变量去储存他
如果要添加到lua环境中只需要在下面写
//将数组添加到全局环境中
lua.set("LuaJava",arrLua);
这时就会把arrLua这个我们创建的lua数组添加到lua的全局环境中并且他会被一个叫LuaJava的变量储存
最后是lua的函数
LuaFunction使用
他就是在Java中创建一个lua中的函数 当然写法和刚刚的luatable是不一样的
这里需要创建一个单独的类 继承VarArgFunction并实现其中的invoke方法
但是这会有一个问题就是类太多了如果一个类一个文件就很难受
当然也可以使用内部类但是这会让代码显得很杂乱
这里奉上我自己是怎么处理的
@Component
public class JavaTableFunction {
//print函数 变长参数
public class print extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
StringBuilder s=new StringBuilder();
//遍历所有的参数并拼接字符串 这里获取的是字符串类型的参数
for (int i = 0; i < args.narg(); i++) {
s.append(args.checkjstring(i+1));
}
System.out.println(s);
return LuaValue.NIL;
}
}
}
我将这些实现类放在另一个类中这部的话不多做介绍了
主要来说说Varargs对象 也就是这里的参数args他可以接收多个参数 这块其实还有一个对象可以写lua的函数 OneArgFunction 这个是一个抽象类 写法也和这里的意义区别是实现方法不一样还有这个只能接收一个参数 平常不怎么用就不介绍了
这里重点介绍的是VarArgFunction中的一些常用方法和LuaValue中的常量
-
narg() 他用于获取参数的数量 返回int类型
-
checkxxx() 他用于获取参数的值 其中还有checboolean和checkint等他们一个是获取int类型的值一个是获取boolean类型的值 其实原理都一样 可以看看源码就懂了 需要注意的是有一些会是checkjxxx会多一个字母
LuaValue中的常量
他里面有很多但是我在实际开发中其实只用到了一个
LuaValue.NIL他表示没有返回值例如在刚刚的LuaFunction使用中返回了一个值而这个值就是LuaValue.NIL
LuaFunction的返回值
如果需要返回字符串等内容直接使用LuaValue.value.Of(字符串)int类型和其他类型同理
返回一个lua数组
如果需要返回数组直接new一个LuaTable对象然后返回就行了
还可以有另一种
@Override
public Varargs invoke(Varargs args) {
LuaTable result = LuaValue.tableOf();
// 将参数添加到结果表中
for (int i = 1; i <= args.narg(); i++) {
result.insert(i, args.arg(i));
}
return result;
}
这样他会把所有参数添加到一个表中而这个LuaValue.tableOf();其实和new没什么区别
返回一个函数
如果想返回一个函数也是直接new一个LuaFunction对象即可
@Override
public Varargs invoke(Varargs args) {
// 创建 Lua 函数
LuaFunction luaFunction = new LuaFunction() {
@Override
public LuaValue call(LuaValue[] args) {
// 在这里编写 Lua 函数的实现
System.out.println("Hello from Lua function!");
return LuaValue.NIL; // 返回 nil
}
};
return luaFunction;
这段代码是从我的项目中抽出来的请不要直接复制黏贴使用
返回Java对象
直接使用CoerceJavaToLua.coerce(Object)即可将Java对象转换成lua的对象然后直接return出去就行
源码:https://github.com/MainWhite/LuaJava-example