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

来源:互联网 发布:手机android编程软件 编辑:程序博客网 时间:2024/05/19 18:40


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")endlocal t2=sys:currentTimeMillis()local t =t2-t1print("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相对对比才能知道差距。


0 0
原创粉丝点击