您的位置:首页 > 编程语言 > Lua

LuaJava:跟着LuaJava一步一步学习JNI -1

2015-10-25 22:45 513 查看
Java 测试代码案例1如下:

LuaState L = LuaStateFactory.newLuaState();
L.openLibs();

LuaObject global_a = L.getLuaObject("global_a");


使用LuaJava第一步就是创建Lua VM虚拟机LuaState . LuaState 由LuaStateFactory 管理。

 LuaState L = LuaStateFactory.newLuaState(); 可以创建一个新LuaState。

但是在LuaState 构造函数中使用_open()本地方法创建LuaVM.

  /**

   * Constructor to instance a new LuaState and initialize it with LuaJava's functions

   * @param stateId

   */

  protected LuaState(int stateId)

  {

    luaState = _open();

    luajava_open(luaState, stateId);

    this.stateId = stateId;

  }

使用的本地方法为:private synchronized native CPtr _open();

在c代码 实现代码为:

************************************************************************/
//由java本地方法生成:LuaState类private synchronized native CPtr _open();
JNIEXPORT jobject JNICALL Java_org_keplerproject_luajava_LuaState__1open(JNIEnv * env , jobject jobj)
{  //通过Lua C API创建LuaVM
lua_State * L = lua_open();
jobject obj;
jclass tempClass;
//通过FindClass()来查找CPtr java类
tempClass = ( *env )->FindClass( env , "org/keplerproject/luajava/CPtr" );
//创建新Java对象
obj = ( *env )->AllocObject( env , tempClass );
if ( obj )
{  //根据类和类字段签名获取类字段
jfieldID _fieldID=( *env )->GetFieldID( env , tempClass , "peer", "J" );
//设置类字段值,这里设置类CPtr 对象obj  字段peer 的值为 L的指针地址。
( *env )->SetLongField( env , obj ,_fieldID  , ( jlong ) L );
}
//同时返回CPtr局部对象。
return obj;
}


在JNI.H头文件中:

class _jobject {};

typedef _jobject *jobject;

在__open()返回值为 jobject obj;  其实就是指针的地址。

/**
* An abstraction for a C pointer data type.  A CPtr instance represents, on
* the Java side, a C pointer.  The C pointer could be any <em>type</em> of C
* pointer.
*/
public class CPtr
{

/**
* Compares this <code>CPtr</code> to the specified object.
*
* @param other a <code>CPtr</code>
* @return      true if the class of this <code>CPtr</code> object and the
*		    class of <code>other</code> are exactly equal, and the C
*		    pointers being pointed to by these objects are also
*		    equal. Returns false otherwise.
*/
public boolean equals(Object other)
{
if (other == null)
return false;
if (other == this)
return true;
if (CPtr.class != other.getClass())
return false;
return peer == ((CPtr)other).peer;
}

/* Pointer value of the real C pointer. Use long to be 64-bit safe. */
//这里其实是保存lua_State * L = lua_open();  L指针的地址
private long peer;

/**
* Gets the value of the C pointer abstraction
* @return long
*/
protected long getPeer()
{
return peer;
}

/* No-args constructor. */
CPtr() {}

}


至此,LuaState 虚拟机创建完成,LuaState在C语言中的指针L的地址,由对象CPtr 中Peer 保存Long 类型的值。

在LuaState 中有 luaopen_java()方法:

  /**

   * Initializes lua State to be used by luajava

   * @param cptr

   * @param stateId

   */

  private synchronized native void luajava_open(CPtr cptr, int stateId);

因为CPtr保存了LuaState 的指针,所以C要获取到Lua VM必须通过CPtr传递参数。

/**
* Creates a reference to an object in the variable globalName
* @param globalName
* @return LuaObject
*/
public LuaObject getLuaObject(String globalName)
{
return new LuaObject(this, globalName);
}


在LuaState.getLuaObject(String globalName) 来获取全局变量时,LuaState 首先创建一个LuaObject 对象来代理Lua 里面的数据类型,

public class LuaObject
{
protected Integer ref;

protected LuaState L;
}


LuaObject 中持有LuaVM虚拟机和Lua对象的引用。

LuaObject 持有Lua对象的引用时通过Lua的引用机制。

JNIEXPORT jint JNICALL Java_org_keplerproject_luajava_LuaState__1Lref
(JNIEnv * env , jobject jobj , jobject cptr , jint t)
{
lua_State * L = getStateFromCPtr( env , cptr );

return ( jint ) luaL_ref( L , ( int ) t );
}

Java 测试代码案例1如下:

hello.lua 代码:

sys = luajava.bindClass("java.lang.System")
local t1=sys:currentTimeMillis()

for i=1,10000 do
local  obj = luajava.newInstance("org.keplerproject.luajava.JavaObject")

end
local t2=sys:currentTimeMillis()

local t =t2-t1
print("lua时间:"..t)


main.java代码:

Object obj =null;
long t1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
obj =new Object();
}
long t2 = System.currentTimeMillis();
System.out.println("java时间:"+(t2-t1));
LuaState L = LuaStateFactory.newLuaState();
L.openLibs();
L.LdoFile("hello.lua");
L.close();
打印结果:

java时间:0

lua时间:156

通过Lua脚本创建java 对象实例明显性能上有差距,来让我们看看具体原因。

luajava.newInstance("org.keplerproject.luajava.JavaObject") 直接调用luajava Table中注册的函数 。

/***************************************************************************
*
*  Function: javaNewInstance
*  ****/

int javaNewInstance( lua_State * L )
{
jint ret;
jmethodID method;
const char * className;
jstring javaClassName;
jthrowable exp;
lua_Number stateIndex;
JNIEnv * javaEnv;

/* Gets the luaState index */
lua_pushstring( L , LUAJAVASTATEINDEX );
lua_rawget( L , LUA_REGISTRYINDEX );

if ( !lua_isnumber( L , -1 ) )
{
lua_pushstring( L , "Impossible to identify luaState id." );
lua_error( L );
}

stateIndex = lua_tonumber( L , -1 );
lua_pop( L , 1 );

/* get the string parameter */
if ( !lua_isstring( L , 1 ) )
{
lua_pushstring( L , "Invalid parameter type. String expected as first parameter." );
lua_error( L );
}

className = lua_tostring( L , 1 );

/* Gets the JNI Environment */
javaEnv = getEnvFromState( L );
if ( javaEnv == NULL )
{
lua_pushstring( L , "Invalid JNI Environment." );
lua_error( L );
}
//以上都是对java的检查
//获取LuaJavaAPI 类的静态函数javaNewInstance 的方法Id
method = ( *javaEnv )->GetStaticMethodID( javaEnv , luajava_api_class , "javaNewInstance" ,
"(ILjava/lang/String;)I" );
//创建一个java string对象
javaClassName = ( *javaEnv )->NewStringUTF( javaEnv , className );
//调用LuaJavaAPI 的javaNewInstance 静态方法,同时传递参数。剩下事情交由java来处理实际创建java对象的功能。
//调用LuaJavaAPI的静态函数,才是该函数最重要的地方,也是通过Lua语言创建java对象的关键。
ret = ( *javaEnv )->CallStaticIntMethod( javaEnv , luajava_api_class , method, (jint)stateIndex ,
javaClassName );
//判断是否发生异常
exp = ( *javaEnv )->ExceptionOccurred( javaEnv );

/* Handles exception */
if ( exp != NULL )
{
jobject jstr;
const char * str;

( *javaEnv )->ExceptionClear( javaEnv );
jstr = ( *javaEnv )->CallObjectMethod( javaEnv , exp , get_message_method );

( *javaEnv )->DeleteLocalRef( javaEnv , javaClassName );

if ( jstr == NULL )
{
jmethodID methodId;

methodId = ( *javaEnv )->GetMethodID( javaEnv , throwable_class , "toString" , "()Ljava/lang/String;" );
jstr = ( *javaEnv )->CallObjectMethod( javaEnv , exp , methodId );
}

str = ( *javaEnv )->GetStringUTFChars( javaEnv , jstr , NULL );

lua_pushstring( L , str );

( *javaEnv )->ReleaseStringUTFChars( javaEnv , jstr, str );

lua_error( L );
}
//对局部引用进行释放
( *javaEnv )->DeleteLocalRef( javaEnv , javaClassName );

return ret;
}


LuaJavaAPI 中静态javaNewInstance 函数源代码:

/**
* Pushes a new instance of a java Object of the type className
*
* @param luaState int that represents the state to be used
* @param className name of the class
* @return number of returned objects
* @throws LuaException
*/
public static int javaNewInstance(int luaState, String className)
throws LuaException
{//根据LuaVM索引来获取虚拟机引用
LuaState L = LuaStateFactory.getExistingState(luaState);

synchronized (L)
{
Class clazz;
try
{//根据类名称利用反射技术获取CLass对象
clazz = Class.forName(className);
}
catch (ClassNotFoundException e)
{
throw new LuaException(e);
}
//创建对象
Object ret = getObjInstance(L, clazz);

L.pushJavaObject(ret);

return 1;
}
}
很明显在Native Code中对于实际功能的处理非常少,还是利用java语言本身提供的特性来实现功能的。仅仅这样测试,虽然有性能问题,但是不知道问题到底有多大,是否能够接受,看样子只能用LuaInterface与LuaJava相对对比才能知道差距。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LuaJava Lua JNI