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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/293288.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python并行编程详解:发挥多核优势的艺术

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在当今计算机时代&#xff0c;充分发挥多核处理器的性能是提高程序运行效率的关键。Python作为一门强大的编程语言&#xff0c;提供了多种并行编程工具和库。本文将深入介绍Python中的并行编程&#xff0c;探讨如…

Python匹配文件模块的实战技巧

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;文件匹配是许多应用中常见的需求&#xff0c;例如文件管理、数据处理等。本文将深入探讨Python中用于文件匹配的模块&#xff0c;包括glob、fnmatch和os.path等&#xff0c;通过丰富的示例…

分享一套国内功能齐全的开源MES/免费MES/MES源代码

一、系统概述&#xff1a; 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES、好看的数字大屏。 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理&#xff0c;车间基础数据管理&#xff0c;计划管理…

Win系统修改Nginx配置结合内网穿透实现远程访问多个Web站点

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…

数据结构之进阶二叉树(二叉搜索树和AVL树、红黑树的实现)超详细解析,附实操图和搜索二叉树的实现过程图

绪论​ “生命有如铁砧&#xff0c;愈被敲打&#xff0c;愈能发出火花。——伽利略”&#xff1b;本章主要是数据结构 二叉树的进阶知识&#xff0c;若之前没学过二叉树建议看看这篇文章一篇掌握二叉树&#xff0c;本章的知识从浅到深的对搜索二叉树的使用进行了介绍和对其底层…

vue2项目安装出现Syntax Error: Error: Cannot find module ‘less‘

一个新项目安装的时候出现下面问题 网上说&#xff0c;一般都是说webpack版本与less-loader版本不匹配引起的 npm view webpack version 查看当然webpack版本 开始直接用npm install less--legacy-peer-deps失败了&#xff0c;跟其它eslint版本好像有冲突&#xff0c;用其它版…

如何开启In-sensor zoom 功能

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、In-sensor zoom 概述二、如何开启 In-sensor zoom2.1 开启 camxsettings.xml setting2.2 多摄像头&#xff0c;需要添加特殊的逻辑2.3 在 MetaTran…

【电路笔记】-串联电容器

串联电容器 文章目录 串联电容器1、概述2、示例13、示例34、总结 当电容器以菊花链方式连接在一条线上时&#xff0c;它们就串联在一起。 1、概述 对于串联电容器&#xff0c;流过电容器的充电电流 ( i C i_C iC​ ) 对于所有电容器来说都是相同的&#xff0c;因为它只有一条…

HW4 Speaker classification-SIMPLE (TRANSFORMER)

Task description Classify the speakers of given features.Main goal: Learn how to use transformer.Baselines:Easy: R

《每天一分钟学习C语言·七》指针、字节对齐等

1、 对于二维数组如a[3][4]可以当做有三个元素的一维数组&#xff0c;每个元素包含四个小元素。 2、 printf(“%-5d”, i); //负号表示左对齐&#xff0c;5d表示空五个光标的位置 3、 栈&#xff1a;先进后出&#xff0c;堆&#xff1a;先进先出 4、 &#xff08;1&#xff…

探讨APP自动化测试工具的重要性

随着移动应用市场的蓬勃发展&#xff0c;企业对于保证其移动应用质量和用户体验的需求日益迫切。在这一背景下&#xff0c;APP自动化测试工具正变得越来越重要&#xff0c;成为企业成功的关键组成部分。本文将探讨APP自动化测试工具对企业的重要性&#xff0c;并为您解析其在提…

EfficientDet:Scalable and Efficient Object Detection中文版 (BiFPN)

EfficientDet: Scalable and Efficient Object Detection EfficientDet&#xff1a;可扩展和高效的目标检测 摘要 模型效率在计算机视觉中变得越来越重要。本文系统地研究了用于目标检测的神经网络架构设计选择&#xff0c;并提出了几个关键的优化方法来提高效率。首先&…