JPYPE用户手册小译

来源:互联网 发布:英雄无敌7 for mac 编辑:程序博客网 时间:2024/05/16 06:39
 

JPYPE用户手册小译

By Jetway from hdu_cloud

1、            概述

JPype是为了python程序能完全访问java类库而开发的。它并不是将像Jython/JPython那样重新用python实现java类库,而是通过两个虚拟机之间的接口实现的。

为什么要开发JPype呢?开发者认为尽管他自身对python编程非常深入,但他并不能否认java的市场占有率。比如sourceforge中就包含了3267个与python相关的项目和12126个与java相关的项目(没算上商业用途的项目)。并且在服务器端python的非常弱小的,就算是Zope,还是比不上java在服务器的应用上的地位。于是为了同时使用这两种语言,开发者搞了这个项目。

那么Jython又如何?Jython不错,但是有很多缺点,比如,它比CPython慢,并且不允许访问大部分Python扩展库。

看一个JPype使用的例子:

from jpype import *
  startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea")
  java.lang.System.out.println("hello world")
  shutdownJVM()

 

这是一个简单的helloworld程序,不过显示了最重要的两个调用:startJVM和shutdownJVM。下一节将详细介绍。

2、            线程

此处唯一的问题是保证java线程和python线程正确的交互,感谢上苍,这个实现起来不难。

Python线程。唯一要注意的只有调用线程内的jpype.attachThreadToJVM(),这样的话JVM就可用了。对于那些不是你自己启动的线程,你可以调用ThreadAttachedToJVM()来检测。

Java线程。因为没有回调机制,当前无法使用java创建的线程。

同步(一致性)。Java同步(一致性)机制可以分为两种:第一种,同步(一致)的关键字,诸如一个方法的前缀和一个方法内部的语句块;第二种,对象类中不同的方法(notify,notify all,wait)。为支持同步(一致性)功能,jpype定义了一个synchronized(O)方法,O必须是一个java对象或者java类或者相当于一个对象的java包(JString和JObject)。此方法的返回值是一个monitor对象,它将在对象O的整个生命周期中保持其一致性(同步)。

3、            性能

Jpype使用JNI,它并不是最有效的接口。并且Jpype桥接两个完全不同的实时环境,需要来回转换。这两个都可能引入巨大的性能瓶颈。

JNI是标准的适用于大部分JVM的本地化接口,要减少JNI负担只能将一部分代码转移到java中。

要减少转换负担,可以对那些给定(一个字符串,一个对象,一个数组等等)并且经常传入java的对象,你可以使用wrappers一次性预转换他们。

4、            内部类

大部分内部类可以像普通类一样使用,只是有以下区别:

在java中使用$来区分内部类和外部类。例如内部类Foo定义在Bar内部,在java中称为Bar.Foo,但此时其真正的名字为Bar$Foo。

由于上述名字变异,你不能使用标准的包访问方式来获取它们。使用JPackage的方法_getclass_来载入。

非静态内部类不能从python代码中实例化。但是可以完全没有问题地使用从java代码中接受到的实例。

5、            数组

Jpype完全支持接受java数组并传递java方法给这些数组。Java数组(打包成JArray包类),其行为很像python列表(list),当然了java数组大小是固定的,而python列表大小是可变的。多维数组也可以很好的在python中运行。

从python中创建java数组。创建java数组用的是JArray方法,代码形式如下:

JArray(type, num_dims)(sz or sequence)

Type是java(String或java对像)类或者包类型。Num_dims是数组大小,默认为1.。sz数组中元素的真实数目。Sequence是初始化数组的序列。JArray(type, ndims)返回的是一个数组类,可以通过此类来生成实例。

6、            类型转换

JPype这个桥接系统中最麻烦的应该是找到python类型和java类型之间的无缝转换。下表列出了转换明细。

其中:none表示无法转换;Explicit(E)表示JPype可以转换成想要的类型,但是只针对与Wrapper类。也就是wrapper类将作为一个参数方位此类型。Implicit(I)表示JPype可以按需转换。Exact>(X),类似implicit,但是当决定哪个方法负载时,exact比implicit具有更高的优先级。

其中:

(1)    如果Python值符合java本地值类型,转换就会发生。

(2)    如果python string或者unicode的长度是1,转化发生

(3)  所要求的对象必须与java.lang.String (java.lang.Object,java.util.Comparable)兼容。

(4)    维数必须能配对,并且类型必须兼容。

(5)    只有当所要求的类型为java.lang.Object

(6)    只有当JObject包的详细类型为一个可兼容的数组类。

(7)    只有当所要求的类型与包的详细类型兼容。实际的java对象并不考虑。

(8)    只有当所要求的类型与java对象的实际类型兼容

(9)    只有当所要求的类型是java.lang.Object或者java.lang.Class

(10)只有当值True和False明确的转换成boolean时。

从java转换到python:

Java的byte,short和int转换成python的int

Java的long转换成python的long

Java的float和double转换成python的float

Java的boolean转换成python int值0或1

Java 的char转换成python 中长度为1 的unicode

Java的String转换成python的unicode

Java的数组转换成JArray

所有的java对象转换成JavaObject

Java类转换成JavaClass

Java数组类转换成JavaArrayClass

7、            JProxy

JProxy的构造函数使用2个参数。第一个参数是一个或者一组(a sequence of)JClass对象,定义要实现的接口。第二个参数必须是一个关键字参数(keyword argument),并且必须是一个dict或者inst。如果dict指定,那么第二个参数必须是一个字典,带关键字的方法名为定义的接口,而且值为可调用的对象。如果inst是一个给定对象实例(定义的给接口修饰的方法)。

当然在python中子类别化java类是不一样的。

样例代码:

假设java接口如下:

public interface ITestInterface2

        {

               int testMethod();

               String testMethod2();

        }

 

你可以创建一个代理并实现此接口,有两种方法,第一种使用类:

class C :
               def testMethod(self) :
                       return 42
                       
               def testMethod2(self) :
                       return "Bar"      
        
        c = C()
        proxy = JProxy("ITestInterface2", inst=c)

 

第二种使用字典:

 
def _testMethod() :
        return 32
 
        def _testMethod2() :
        return "Fooo!" 
               
        d = {
               'testMethod' : _testMethod,
               'testMethod2' : _testMethod2,
        }

proxy = JProxy("ITestInterface2", dict=d

 

8、            java异常

python异常是扩展类,在表面上与java类差不多(常规类),但是python异常与常规python类完全不同,这导致了完全直接的捕获java异常是不可能的。

所有的抛出的java异常都会结束于抛出jpype.JavaException异常。你可以接下来使用message(), stackTrace() 和javaClass()来访问扩展信息。例子如下:

        try :
                    # Code that throws a java.lang.RuntimeException
          except JavaException, ex :
                    if JavaException.javaClass() is java.lang.RuntimeException :
                               print "Caught the runtime exception : ", JavaException.message()
                               print JavaException.stackTrace()

 

你可以直接使用JException来捕获真正的java异常:

        try :
                    # Code that throws a java.lang.RuntimeException
          except jpype.JException(java.lang.RuntimeException), ex :
                    print "Caught the runtime exception : ", JavaException.message()
                    print JavaException.stackTrace()

 

9、            已知的局限性

卸载JVM。JNI API中定义了destroyJVM()的方法,但是由于Sun公司的JVM不允许卸载,此方法形同虚设。所以当你在shutdownJVM()之后尝试着再次调用startJVM(),你将会受到一个不明确的(non-specific)异常。JPype中并没有出错。

方法依赖于现存的类。Java库中有一些方法依赖于寻找调用类时的信息。如果直接从python代码中调用会出错。JNI API没有提供类似的方法。

 

A.     Module Reference

startJVM()方法。此方法必须必须在任何jpype features被使用前调用。返回值为None。异常,RuntimeException。参数:

vmPath  jvm.dll或者jvm.so(这个看具体平台的)的路径。

misc arguments  可选,可以通过此参数将任何命令行参数传递给JVM。

 

shutdownJVM()方法。没有参数,返回值None。异常RuntimeException。

 

attachThreadToJVM方法。大部分情况下不用调用,jpype module会自动执行。没有参数,返回值None,异常为RuntimeException

 

isTreadAttachedToJVM方法。这个也是不大用调用的。参数没有,返回值None,异常RuntimeException。

detachThreadFromJVM方法。不太需要手动调用。参数没有,返回值None,异常RuntimeException

 

synchronized方法。不太需要手动调用。参数没有,返回值None,异常RuntimeException

JPackage类。此包允许结构化方位java包和类。只需要在JPackage中声明包树的根(the root of the package tree)。例如:

要导入w3c DOM包:Document = JPackage(‘arg’).w3c.dom.Document

 

Wrapper classes。封装java类和方法到python中的主要问题在于,java允许重载一个方法。大部分情况下是没什么问题的。大部分重载的方法有不一样的参数并且不会发生冲撞。

当jpype不能决定调用哪个重载的方法时,用户必须解决这个歧义。于是就可以引入wrapper类了。例子为java.io.PrintStream类,它有两种可变的方法print和println。

对于以下代码,Jpype会自动的选择println(int)方法。

from jpype import *
 startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea")
 java.lang.System.out.println(1)
 shutdownJVM()

 

改过之后:

from jpype import *
 startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea")
 java.lang.System.out.println(JByte(1)) # <--- wrap the 1 in a JByte
 shutdownJVM()

告诉jpype选择byte类型,但是这个wrappered类型要求必须与要求类型兼容,于是使用JByte wrapper来请求一个int会失败。

(到此为止吧,jetway水平有限,但是若要转载或使用此文,请挂上jetway的名字啊嘿嘿——原文地址:http://jpype.sourceforge.net/doc/user-guide/userguide.html)

原创粉丝点击