当前位置: 首页 > news >正文

LuaJava操作Java的方法

     最近在学习lua,然后顺便看了下luaj,可能用的人比较少,网上关于luaj的文章较少,其中在网上找到这个博主的相关文章,很详细,对于要学习luaj的小伙伴可以两篇一起查看,本文在此基础上进行扩展。
     本文的luaj版本是:luaj-3.0.1

珠玉在前》》》》Luaj学习笔记(二) - 在Lua中操作Java对象

LuaJ源码中org.luaj.vm2.lib.jse.LuajavaLib,是我们在lua中操作java的主要方法库定义。
在这里插入图片描述

luajava有五种方法让我们操作java类:bindClasnewInstancenewcreateProxyloadLib

先放上源码,然后我们一步步解析,bindClasnewInstancenew 使用方案和案例在前一篇文章就已经解释过了,这里不做过多赘述,对于前篇不详细的createProxyloadLib做重点介绍:

public Varargs invoke(Varargs args) {try {switch ( opcode ) {case INIT: {// LuaValue modname = args.arg1();LuaValue env = args.arg(2);LuaTable t = new LuaTable();bind( t, this.getClass(), NAMES, BINDCLASS );env.set("luajava", t);env.get("package").get("loaded").set("luajava", t);return t;}case BINDCLASS: {final Class clazz = classForName(args.checkjstring(1));return JavaClass.forClass(clazz);}case NEWINSTANCE:case NEW: {// get constructorfinal LuaValue c = args.checkvalue(1); final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));final Varargs consargs = args.subargs(2);return JavaClass.forClass(clazz).getConstructor().invoke(consargs);}case CREATEPROXY: {				final int niface = args.narg()-1;if ( niface <= 0 )throw new LuaError("no interfaces");final LuaValue lobj = args.checktable(niface+1);// get the interfacesfinal Class[] ifaces = new Class[niface];for ( int i=0; i<niface; i++ ) ifaces[i] = classForName(args.checkjstring(i+1));// create the invocation handlerInvocationHandler handler = new ProxyInvocationHandler(lobj);// create the proxy objectObject proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);// return the proxyreturn LuaValue.userdataOf( proxy );}case LOADLIB: {// get constructorString classname = args.checkjstring(1);String methodname = args.checkjstring(2);Class clazz = classForName(classname);Method method = clazz.getMethod(methodname, new Class[] {});Object result = method.invoke(clazz, new Object[] {});if ( result instanceof LuaValue ) {return (LuaValue) result;} else {return NIL;}}default:throw new LuaError("not yet supported: "+this);}} catch (LuaError e) {throw e;} catch (InvocationTargetException ite) {throw new LuaError(ite.getTargetException());} catch (Exception e) {throw new LuaError(e);}}

bindclass

bindclass:返回一个JavaClass的类,该类是对我们参数指定的java类的一个包装。bindClass方法返回类实例class,同时可以调用类实例的new方法生成该class的实例object,然后就可以调用实例方法(实例化的调用这一点和学lua时的面向对象的写法很相似)

该方法适合调用java类的静态方法静态属性,当然也可以用来实例化对象,但newInstance 和 new更符合语义

源码:

			case BINDCLASS: {final Class clazz = classForName(args.checkjstring(1));return JavaClass.forClass(clazz);}JavaClassstatic final LuaValue NEW = valueOf("new");static JavaClass forClass(Class var0) {JavaClass var1 = (JavaClass)classes.get(var0);if (var1 == null) {classes.put(var0, var1 = new JavaClass(var0));}return var1;}public LuaValue getConstructor() {return this.getMethod(NEW);}

测试java代码:

public class TestClass {public String s1;protected String s2;private String s3;public static String s4;public String method001(){        return "method001";    }protected void method002(){    }private void method003(){    }public static String method004(){        return "method004";    }
}

lua脚本:

local className = "com.test.luaj.TestClass"local classx = luajava.bindClass(className)
print("静态方法调用:",classx:method004())
print("静态属性值:",classx.s4)local obj = classx:new()
print("实例方法调用:",obj:method001())
print("实例属性值:",obj.s1)

输出结果:

静态方法调用:	method004
静态属性值:	s4
实例方法调用:	method001
实例方法调用:	s1

其中,我们在lua脚本中用类实例调用:new()方法时,实际是invoke JavaClass的new方法,而这个new方法通过getMethod方法拿到的是他的构造器方法(在下一个方法源码中)

newInstance || new

通过源码可以看到 newInstance 和 new方法的大部分逻辑是一致的

入参是有区别的:

  1. newInstance 方法,接受一个字符串的类路径然后转换为Class实例;
  2. new方法接受一个LuaValue对象,从中拿出userdata数据,而这个userdata数据是一个Class实例
    而上一个方法bindClass返回的就是一个包装了Class的LuaValue对象,因此我们可知,在使用new方法的时候,需要先用bindClass方法生成一个Class实例出来,而newInstance就不用了

      然后代码对我们在lua中传入的参数,截取后边的一段用作构造器参数,然后调用我们在上一个方法看到JavaClass.forClass包装Class实例,然后获取该类的构造器,然后invoke调用构造器方法,生成对象

源码:

			case NEWINSTANCE:case NEW: {// get constructorfinal LuaValue c = args.checkvalue(1); final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class));final Varargs consargs = args.subargs(2);return JavaClass.forClass(clazz).getConstructor().invoke(consargs);}JavaClasspublic LuaValue getConstructor() {return getMethod(NEW);}LuaValue getMethod(LuaValue key) {
···Map map = new HashMap();Constructor[] c = ((Class)m_instance).getConstructors();List list = new ArrayList();for ( int i=0; i<c.length; i++ ) if ( Modifier.isPublic(c[i].getModifiers()) )list.add( JavaConstructor.forConstructor(c[i]) );switch ( list.size() ) {case 0: break;case 1: map.put(NEW, list.get(0)); break;default: map.put(NEW, JavaConstructor.forConstructors( (JavaConstructor[])list.toArray(new JavaConstructor[list.size()]) ) ); break;}
···
}

测试代码:

local className = "com.test.luaj.TestClass"local classx = luajava.bindClass(className)
local obj = luajava.new(classx)
print("实例方法调用:",obj:method001())
print("实例属性值:",obj.s1)
print("-----------")local obj2 = luajava.newInstance(className)
print("newInstance>实例方法调用:",obj2:method001())
print("newInstance>实例属性值:",obj2.s1)

输出结果:

new>实例方法调用:	method001
new>实例属性值:	s1
-----------
newInstance>实例方法调用:	method001
newInstance>实例属性值:	s1

createProxy

       createProxy可以像JDKProxy那样的在lua中创建对一个对象的一个或多个方法的代理
       事实上,createProxy使用的代理就是JDKProxy,只不过在用法上和我们通常的用法有些许变动,在最终的方法的invoke时,并不是通常的使用JAVA反射中的的Method的invoke,而是Luaj自己LuaValue的invoke,也就是说通过调用在lua脚本中定义的那个扩展方法,去实现代理,实际上的代理逻辑都在lua中定义(下面lua脚本可以看出来)
       还有很重要的一点,在lua中通过createproxy生成出来的代理对象,是不能在lua脚本中去直接调用代理对象的方法的,?????只能通过将该代理对象当做参数通过调用类方法或者对象方法之后在java中去触发代理对象的方法。(看下边的测试lua源码)

源码:

			case CREATEPROXY: {				final int niface = args.narg()-1;if ( niface <= 0 )throw new LuaError("no interfaces");final LuaValue lobj = args.checktable(niface+1);// get the interfacesfinal Class[] ifaces = new Class[niface];for ( int i=0; i<niface; i++ ) ifaces[i] = classForName(args.checkjstring(i+1));// create the invocation handlerInvocationHandler handler = new ProxyInvocationHandler(lobj);// create the proxy objectObject proxy = Proxy.newProxyInstance(getClass().getClassLoader(), ifaces, handler);// return the proxyreturn LuaValue.userdataOf( proxy );}

在这里插入图片描述

测试java代码:

public interface Car {void running(String carName);void blow(Integer num);}
-------------------------------------------------
public  class Taxi implements Car {@Overridepublic void running(String carName) {System.out.println("The taxi["+carName+"] is running.");}@Overridepublic void blow(Integer num) {for (int i = 0; i < num; i++) {System.out.print("didi\n");}System.out.print("");}public static void triggerProxy(Car car){String carName = UUID.randomUUID().toString();car.running(carName);System.out.println("--------");car.blow((int)Math.random()*10+1);}}
-----------------------------------------------------public class LuaJCreateProxyTest {public static void main(String[] args) throws ScriptException {createProxy002();}static void createProxy002() throws ScriptException {Globals globals = JsePlatform.standardGlobals();globals.loadfile("res/lua/createProxyTest02.lua").call();}
}

lua脚本:

    interfaceName = "com.test.luaj.Car"className = "com.test.luaj.Taxi"taxi = luajava.newInstance(className)-- InvocationHandlerlocal exit_cb = {running = function (carname)print("这是对Car的代理逻辑----前")taxi:running(carname)print("这是对Car的代理逻辑----后")end,blow = function(num)print("Car--blow----前")taxi:blow(num)print("Car--blow----后")end}proxyObj = luajava.createProxy(interfaceName ,exit_cb)-- proxyObj.running()   -- 会报错,不能这样使用--必须通过传参给java方法,在java代码中去调用代理对象的方法luajava.bindClass(className):triggerProxy(proxyObj)

输出结果:

这是对Car的代理逻辑----前
The taxi[74f253d1-c0d8-47ea-9799-01401174abe4] is running.
这是对Car的代理逻辑----后
--------
Car--blow----前
didi
Car--blow----后

loadLib

关于loadLib这个方法,前边文章可能由于历史更新的原因,在luaj-3.0.1版本中代码是不对的
     loadLib通过源码查看我,我们其实可以看到,他只用两个参数,第一个是类路径,第二个是静态方法名,这个方法要么返回一个LuaValue类型的结果,要么不返回或者其他返回类型都会被loadLib转为nil

源码:

case LOADLIB: {// get constructorString classname = args.checkjstring(1);String methodname = args.checkjstring(2);Class clazz = classForName(classname);Method method = clazz.getMethod(methodname, new Class[] {});Object result = method.invoke(clazz, new Object[] {});if ( result instanceof LuaValue ) {return (LuaValue) result;} else {return NIL;}}

测试java源码:

    public static LuaInteger xxx() throws ScriptException {System.out.println("xxx执行啦!\t"+(int)Math.pow(14,2));return LuaValue.valueOf((int)Math.pow(14,2));}static void test007() throws ScriptException {Globals globals = JsePlatform.standardGlobals();globals.loadfile("res/lua/loadLibTest.lua").call();}

lua脚本

local className = "com.yangsong.luaj.LuaJTest"
local method = 'xxx'
local _, result = luajava.loadLib(className, method)
print(_,result)

输出结果:

xxx执行啦!	
196	nil

总结

bindClass适合做类的静态方法和静态属性的取值的操作,也是使用new方法的前置操作。
newInstancenew适合用作java对象实例化之后对实例对象的操作和取值
createProxy适合用作JDKProxy的替代用法,需要注意的是在被代理对象和代理对象都在脚本中生成,且代理对象不能直接在lua中去调用代理方法执行,需要以传参的形式给到java方法调用java方法触发。
loadLib用于类的无参静态方法的调用,如果需要返回值,则需要定义方法返回类型为LuaValue

相关文章:

LuaJava操作Java的方法

最近在学习lua&#xff0c;然后顺便看了下luaj&#xff0c;可能用的人比较少&#xff0c;网上关于luaj的文章较少&#xff0c;其中在网上找到这个博主的相关文章&#xff0c;很详细&#xff0c;对于要学习luaj的小伙伴可以两篇一起查看&#xff0c;本文在此基础上进行扩展。 …...

oracle怎样才算开启了内存大页?

oracle怎样才算开启了内存大页&#xff1f; 关键核查下面三点&#xff1a; 1./etc/sysctl.conf vm.nr_hugepages16384这是给了32G&#xff0c;计划sga给30G&#xff0c;一般需多分配2-4G sysctl -p生效 看cat /proc/meminfo|grep Huge啥结果&#xff1f; 这种明显是配了…...

【halcon深度学习之那些封装好的库函数】determine_dl_model_detection_param

determine_dl_model_detection_param 目标检测的数据准备过程中的有一个库函数determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议…...

跟着我学Python进阶篇:01.试用Python完成一些简单问题

往期文章 跟着我学Python基础篇&#xff1a;01.初露端倪 跟着我学Python基础篇&#xff1a;02.数字与字符串编程 跟着我学Python基础篇&#xff1a;03.选择结构 跟着我学Python基础篇&#xff1a;04.循环 跟着我学Python基础篇&#xff1a;05.函数 跟着我学Python基础篇&#…...

neo4j-Py2neo使用

neo4j-Py2neo(一)&#xff1a;基本库介绍使用 py2neo的文档地址&#xff1a;https://neo4j-contrib.github.io/py2neo/ py2neo的本质是可以采用两种方式进行操作&#xff0c;一种是利用cypher语句&#xff0c;一种是使用库提供的DataTypes&#xff0c;Data类的实例需要和远程…...

uint29传输格式

前言 不知道谁想出来的。 反正我是想不到。 我看网上也没人讲这个。 写篇博客帮一下素未谋面的网友。 uint29 本质上是网络传输的时候&#xff0c;借用至多4字节Bytes&#xff0c;表达29位的无符号整数。 读8位数字&#xff0c;判断小于128? 是的话&#xff0c;返回末7位…...

Linux:终端定时自动注销

这样防止了&#xff0c;当我们临时离开电脑这个空隙&#xff0c;被坏蛋给趁虚而入 定几十秒或者分钟&#xff0c;如果这个时间段没有输入东西那么就会自动退出 全局生效 这个系统中的所有用户生效 vim /etc/profile在末尾加入TMOUT10 TMOUT10 这个就是10 秒&#xff0c;按…...

STM32F103RCT6开发板M3单片机教程06--定时器中断

前言 除非特别说明&#xff0c;本章节描述的模块应用于整个STM32F103xx微控制器系列&#xff0c;因为我们使用是STM32F103RCT6开发板是mini最小系统板。本教程使用是&#xff08;光明谷SUN_STM32mini开发板&#xff09; STM32F10X定时器(Timer)基础 首先了解一下是STM32F10X…...

数据库故障Waiting for table metadata lock

场景&#xff1a;早上来发现一个程序&#xff0c;链接mysql数据库有点问题&#xff0c;随后排查&#xff0c;因为容器在k8s里面。所以尝试重启了pod没有效果 一、重启pod: 这里是几种在Kubernetes中重启Pod的方法: 删除Pod,利用Deployment重建 kubectl delete pod mypodDepl…...

Springboot数据校验与异常篇

一、异常处理 1.1Http状态码 HTTP状态码是指在HTTP通信过程中&#xff0c;服务器向客户端返回的响应状态。它通过3位数字构成&#xff0c;第一个数字定义了响应的类别&#xff0c;后两位数字没有具体分类作用。以下是常见的HTTP状态码及其含义&#xff1a; - 1xx&#xff08;信…...

第三十六章 XML 模式的高级选项 - 创建子类型的替换组

文章目录 第三十六章 XML 模式的高级选项 - 创建子类型的替换组创建子类型的替换组将子类限制在替换组中 第三十六章 XML 模式的高级选项 - 创建子类型的替换组 创建子类型的替换组 XML 模式规范还允许定义替换组&#xff0c;这可以是创建选择的替代方法。语法有些不同。无需…...

堆与二叉树(上)

本篇主要讲的是一些概念&#xff0c;推论和堆的实现&#xff08;核心在堆的实现这一块&#xff09; 涉及到的一些结论&#xff0c;证明放到最后&#xff0c;可以选择跳过&#xff0c;知识点过多&#xff0c;当复习一用差不多&#xff0c;如果是刚学这一块的&#xff0c;建议打…...

HBase查询的一些限制与解决方案

Apache HBase 是一个开源的、非关系型、分布式数据库&#xff0c;它是 Hadoop 生态系统的一部分&#xff0c;用于存储和处理大量的稀疏数据。HBase 在设计上是为了提供快速的随机读写能力&#xff0c;但与此同时&#xff0c;它也带来了一些查询上的限制&#xff1a; 没有SQL支持…...

软件开发 VS Web开发

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 目录 介绍&#xff1a; 角色和职责&#xff1a; 软件开发人员&#xff1a; Web开发人员&#xff1a; 技能&#xff1a; 软件开发人员&#xff1a; Web开发人…...

基于Springboot的旅游网站设计与实现(论文+调试+源码)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…...

【从零开始学习--设计模式--策略模式】

返回首页 前言 感谢各位同学的关注与支持&#xff0c;我会一直更新此专题&#xff0c;竭尽所能整理出更为详细的内容分享给大家&#xff0c;但碍于时间及精力有限&#xff0c;代码分享较少&#xff0c;后续会把所有代码示例整理到github&#xff0c;敬请期待。 此章节介绍策…...

条款6:若不想使用编译器自动生成的函数,就该明确拒绝

有些场景我们不需要编译器默认实现的构造函数&#xff0c;拷贝构造函数&#xff0c;赋值函数&#xff0c;这时候我们应该明确的告诉编译器&#xff0c;我们不需要&#xff0c;一个可行的方法是将拷贝构造函数和赋值函数声明为private。 class HomeForSale { ... }; HomeForSal…...

零基础也能制作家装预约咨询小程序

近年来&#xff0c;随着互联网的快速发展&#xff0c;越来越多的消费者倾向于使用手机进行购物和咨询。然而&#xff0c;许多家装实体店却发现自己的客流量越来越少&#xff0c;急需一种新的方式来吸引顾客。而开发家装预约咨询小程序则成为了一种利用互联网技术来解决这一问题…...

Mybatis的插件运⾏原理,如何编写⼀个插件?

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…...

C++复合数据类型:字符数组|读取键盘输入|简单读写文件

文章目录 字符数组&#xff08;C风格字符串&#xff09;读取键盘输入使用输入操作符读取单词读取一行信息getline使用get读取一个字符 读写文件 字符数组&#xff08;C风格字符串&#xff09; 字符串就是一串字符的集合&#xff0c;本质上其实是一个“字符的数组”。 在C中为了…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...