写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫码加微信好友进【程序员面试学习交流群】,免费领取。也欢迎各位一起在群里探讨技术。

写在前面

在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢。当然,之所以要面对这个问题,或许是因为一些历史原因,或者仅仅是为了简单。恰好我在项目中就遇到了这个问题,需要在Java程序中调用Python程序。关于在Java中调用Python程序的实现,根据不同的用途可以使用多种不同的方法,在这里就将在Java中调用Python程序的方式做一个总结。

直接通过Runtime进行调用

我们知道,在Java中如果需要调用第三方程序,可以直接通过Runtime实现,这也是最直接最粗暴的做法。


public class InvokeByRuntime {/*** @param args* @throws IOException * @throws InterruptedException */public static void main(String[] args) throws IOException, InterruptedException {String exe = "python";String command = "D:\calculator_simple.py";String num1 = "1";String num2 = "2";String[] cmdArr = new String[] {exe, command, num1, num2};Process process = Runtime.getRuntime().exec(cmdArr);InputStream is = process.getInputStream();DataInputStream dis = new DataInputStream(is);String str = dis.readLine();process.waitFor();System.out.println(str);}}

输出:

3

calculator_simple.py:


# coding=utf-8from sys import argvnum1 = argv[1]num2 = argv[2]sum = int(num1) + int(num2)print sum

显然,在Java中通过Runtime调用Python程序与直接执行Python程序的效果是一样的,可以在Python中读取传递的参数,也可以在Java中读取到Python的执行结果。需要注意的是,不能在Python中通过return语句返回结果,只能将返回值写入到标准输出流中,然后在Java中通过标准输入流读取Python的输出值。

通过Jython调用

通过Jython调用Python?我在听到这个概念的时候一脸懵逼,不是说好的在Java中调用Python程序吗?这个Jython是什么鬼?难道是一个在Java中调用Python程序的组件或工具?其实,关于Jython是什么这个疑问,我估计有许多人在一开始接触的时候也是很疑惑的,下面我们就一一道来。

1. 什么是Jython

Jython主页:http://www.jython.org/currentdocs.html

按照官方的定义,Jython是Python语言在Java平台的实现。这个概念似乎有点拗口,反正我一开始并没有理解。Python难道不已经是一门语言了吗?什么叫做Jython是Python语言在Java平台的实现?

实际上,之所以存在这样的困惑主要是因为我们对Python语言的相关概念掌握和理解不清楚导致的。

Python其实只是一个语言规范,它存在多个不同语言实现的版本。具体来说,目前Python语言存在如下几个具体实现:

(1)CPython:CPython是标准Python,也是其他Python编译器的参考实现。通常提到“Python”一词,都是指CPython。CPython由C编写,将Python源码编译成CPython字节码,由虚拟机解释执行。没有用到JIT等技术,垃圾回收方面采用的是引用计数。

(2)Jython:Jython是在JVM上实现的Python,由Java编写。Jython将Python源码编译成JVM字节码,由JVM执行对应的字节码。因此能很好的与JVM集成,比如利用JVM的垃圾回收和JIT,直接导入并调用JVM上其他语言编写的库和函数。

(3)IronPython:IronPython与Jython类似,所不同的是IronPython在CLR上实现的Python,即面向.NET平台,由C#编写。IronPython将源码编译成TODO CLR,同样能很好的与.NET平台集成。即与Jython相同,可以利用.NET框架的JIT、垃圾回收等功能,能导入并调用.NET上其他语言编写的库和函数。IronPython默认使用Unicode字符串。

(4)PyPy:这里说的PyPy是指使用RPython实现,利用Tracing JIT技术实现的Python,而不是RPython工具链。PyPy可以选择多种垃圾回收方式,如标记清除、标记压缩、分代等。

(5)Pyston:Pyston由Dropbox开发,使用C++11编写,采用Method-at-a-time-JIT和Mark Sweep——Stop the World的GC技术。Pyston使用类似JavaScript V8那样的多层编译,其中也用到了LLVM来优化代码。

所以,我们现在再来理解什么是Jython就非常清楚了:Jython是Python语言规范在Java平台的具体实现。具体来说,可以将Python源码编译为JVM可以解释执行的字节码。

Jython原本叫做JPython,于1997年由Jim Hugunin创建,后来在1999年2.0版本发布的时候由Barry Warsaw更名为Jython,在这里我们就不再深究为什么要把JPython更名为Jython的原因了。注意: Jython从2.0版本开始就与CPython的版本保持一致,即:Jython 2.7与CPython 2.7保持对应。

虽然我们理解了什么是Jython,但是还存在一个疑问,为什么Python语言存在这么多不同语言的实现呢?为什么不能就只存在一个C语言实现的版本就可以了呢?存在这么多版本,真的给初学者带来了许多困惑。

当然,要回答这个问题可能就需要深究一些历史的原因了,就此打住。我们在此只讨论使用Jython能做什么以及如何使用Jython?

2. 使用Jython能做什么

既然Jython是Python语言在Java平台的实现,是Java语言实现的,那么是否可以在Jython程序中调用Java,在Java中也能调用Jython呢?

答案是肯定的,实际上,Jython的主要通途就是在Java中调用Python程序;而且,还可以直接在Jython程序中引用Java。

3. 如何使用Jython

3.1 安装Jython

在Jython的官方下载页面我们可以看到如下描述(详见:http://www.jython.org/downloads.html)

显然,可以下载2个Jython的jar包。其中,jython-installer-${version}.jar是用于安装Jython的,jython-standalone-${version}.jar用于嵌入到Java程序中使用。

什么意思?我一开始也是很疑惑,为什么要提供2个不同的jar包呢?他们有什么不同呢?2个不同的Jar包如何使用呢?

首先,jython-installer-${version}.jar用于安装Jython,就好比我们需要安装JRE,用于运行Java程序。除此之外,当需要在Python程序中引用一些公共的第三方库时,也需要先安装Jython才能下载所依赖的模块。

下载jython-installer-${version}.jar完毕之后,进入控制台,执行如下命令:


java -jar jython-installer-${version}.jar

此时会弹出一个图形化的安装界面,只需要一步一步选择相应参数进行安装即可。安装完毕之后,请将Jython安装目录添加为环境变量JYTHON_HOME,同时添加bin目录到PATH变量中:PATH=$PATH:$JYTHON_HOME/bin

进入控制台,执行如下命令就可以进入Jython的交互环境,这与CPython(我们通常说的Python)的命令行交互环境是一样的。


> jythonJython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_121Type "help", "copyright", "credits" or "license" for more information.>>> print("hello,world")hello,world>>>

当然,我们还可以使用jython命令运行一个Python程序。


> jython helloworld.pyhello,world

helloworld.py:


import sysprint("hello,world")

上面我们看到在Jython官网提供了2个Jar包,一个用于安装Jython,执行Python程序。那么,jython-standalone-${version}.jar又有什么用途呢?

实际上,当我们需要在Java中调用Python程序时,除了直接使用Java的Runtime调用,还可以直接使用Jython的API进行调用,而且通过Jython API可以直接调用Python程序中的指定函数或者对象方法,粒度更加精细。

当我们需要调用Jython的API时有两种方式:

第一,如果项目使用Maven进行构建,可以直接添加Jython的依赖配置到pom.xml文件中,如:

<dependency><groupId>org.python</groupId><artifactId>jython</artifactId><version>2.7.0</version></dependency>

第二,可以直接将jython-standalone-${version}.jar添加到项目classpath中,这样也可以调用Jython的相关API了。也就是说,jython-standalone-${version}.jar就是一个提供Jython API的jar独立jar包。

3.2 Java调用Python程序实践

Java通过Jython API调用Python程序,有几种用法:

(1)在Java中执行Python语句,相当于在Java中嵌入了Python程序,这种用法不常见,也没有太大的实际意义。


public static void main(String[] args) {System.setProperty("python.home", "D:\jython2.7.0");PythonInterpreter interp = new PythonInterpreter();// 执行Python程序语句interp.exec("import sys");interp.set("a", new PyInteger(42));interp.exec("print a");interp.exec("x = 2+2");PyObject x = interp.get("x");System.out.println("x: " + x);}

输出:

42x: 4

(2)在Java中简单调用Python程序,不需要传递参数,也不需要获取返回值。


public static void main(String[] args) throws IOException {System.setProperty("python.home", "D:\jython2.7.0");String python = "D:\simple_python.py";PythonInterpreter interp = new PythonInterpreter();interp.execfile(python);interp.cleanup();interp.close();}

simple_python.py:


# coding=utf-8print("Do simple thing in Python")print("输出中文")

(3)在Java中单向调用Python程序中的方法,需要传递参数,并接收返回值。Python既支持面向函数式编程,也支持面向对象编程。因此,调用Python程序中的方法也分别以面向函数式编程和面向对象式编程进行说明。


public static void main(String[] args) throws IOException {System.setProperty("python.home", "D:\jython2.7.0");// 1. Python面向函数式编程: 在Java中调用Python函数String pythonFunc = "D:\calculator_func.py";PythonInterpreter pi1 = new PythonInterpreter();// 加载python程序pi1.execfile(pythonFunc);// 调用Python程序中的函数PyFunction pyf = pi1.get("power", PyFunction.class);PyObject dddRes = pyf.__call__(Py.newInteger(2), Py.newInteger(3));System.out.println(dddRes);pi1.cleanup();pi1.close();// 2. 面向对象式编程: 在Java中调用Python对象实例的方法String pythonClass = "D:\calculator_clazz.py";// python对象名String pythonObjName = "cal";// python类名String pythonClazzName = "Calculator";PythonInterpreter pi2 = new PythonInterpreter();// 加载python程序pi2.execfile(pythonClass);// 实例化python对象pi2.exec(pythonObjName + "=" + pythonClazzName + "()");// 获取实例化的python对象PyObject pyObj = pi2.get(pythonObjName);// 调用python对象方法,传递参数并接收返回值PyObject result = pyObj.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)}); double power = Py.py2double(result);System.out.println(power);pi2.cleanup();pi2.close();}

输出:

8.08.0

calculator_func.py:


# coding=utf-8import math# 面向函数式编程def power(x, y):return math.pow(x, y)

calculator_clazz.py:


# coding=utf-8import math# 面向对象编程class Calculator(object):# 计算x的y次方def power(self, x, y):return math.pow(x,y)

(4)高级调用,也是在Java中调用Python程序最常见的用法:Python程序可以实现Java接口,在Python中也可以调用Java方法。


public static void main(String[] args) throws IOException {System.setProperty("python.home", "D:\jython2.7.0");// Python程序路径String python = "D:\python\fruit_controller.py";// Python实例对象名String pyObjName = "pyController";// Python类名String pyClazzName = "FruitController";Fruit apple = new Apple();Fruit orange = new Orange();PythonInterpreter interpreter = new PythonInterpreter();// 如果在Python程序中引用了第三方库,需要将这些被引用的第三方库所在路径添加到系统环境变量中// 否则,在执行Python程序时将会报错: ImportError: No module named xxxPySystemState sys = interpreter.getSystemState();sys.path.add("D:\python");// 加载Python程序interpreter.execfile(python);// 实例 Python对象interpreter.exec(pyObjName + "=" + pyClazzName + "()");// 1.在Java中获取Python对象,并将Python对象转换为Java对象// 为什么能够转换? 因为Python类实现了Java接口,通过转换后的Java对象只能调用接口中定义的方法GroovyController controller = (GroovyController) interpreter.get(pyObjName).__tojava__(GroovyController.class);controller.controllFruit(apple);controller.controllFruit(orange);// 2.在Java直接通过Python对象调用其方法// 既可以调用实现的Java接口方法,也可以调用Python类自定义的方法PyObject pyObject = interpreter.get(pyObjName);pyObject.invoke("controllFruit", Py.java2py(apple));pyObject.invoke("controllFruit", Py.java2py(orange));pyObject.invoke("printFruit", Py.java2py(apple));pyObject.invoke("printFruit", Py.java2py(orange));// 3.在Java中获取Python类进行实例化对象: 没有事先创建 Python对象PyObject pyClass = interpreter.get("FruitController");PyObject pyObj = pyClass.__call__();pyObj.invoke("controllFruit", Py.java2py(apple));pyObj.invoke("controllFruit", Py.java2py(orange));PyObject power = pyObj.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)});if(power != null) {double p = Py.py2double(power);System.out.println(p);}interpreter.cleanup();interpreter.close();}

输出:

Show: I am a java apple.controllFruit Python ApplecontrollFruit ENDShow: I am a java orange.controllFruit Python OrangecontrollFruit ENDShow: I am a java apple.controllFruit Python ApplecontrollFruit ENDShow: I am a java orange.controllFruit Python OrangecontrollFruit ENDShow: I am a java apple.printFruit Python AppleprintFruit ENDShow: I am a java orange.printFruit Python OrangeprintFruit ENDShow: I am a java apple.controllFruit Python ApplecontrollFruit ENDShow: I am a java orange.controllFruit Python OrangecontrollFruit END8.0

fruit_controller.py:


# coding=utf-8from calculator_clazz import Calculatorfrom java.lang import Stringfrom org.test.inter import GroovyControllerfrom org.test.inter import Fruit# 在Python中实现Java接口: org.test.inter.GroovyControllerclass FruitController(GroovyController):# 实现接口方法def controllFruit(self, fruit):# 在Python中调用Java对象方法fruit.show()if(fruit.getType() == "apple"):print ("controllFruit Python Apple")if(fruit.getType() == "orange"):print ("controllFruit Python Orange")print ("controllFruit END")# 自定义新方法    def printFruit(self, fruit):fruit.show()if(fruit.getType() == "apple"):print ("printFruit Python Apple")if(fruit.getType() == "orange"):print ("printFruit Python Orange")print ("printFruit END")# 引用第三方python程序def power(self, x, y):cal = Calculator()return cal.power(x, y)

Java接口和实现类:


// 该接口用于在Python中实现public interface GroovyController {public void controllFruit(Fruit fruit);}// 在Java中使用的接口public interface Fruit {public String getName();public String getType();public void show();}// Applepublic class Apple implements Fruit {public String getName() {return "java apple";}public String getType() {return "apple";}public void show() {System.out.println("Show: I am a java apple.");}}// Orangepublic class Orange implements Fruit {public String getName() {return "ava orange";}public String getType() {return "orange";}public void show() {System.out.println("Show: I am a java orange.");}}

另外,对于在eclipse中运行时控制台报错:

Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0

请添加VM参数:-Dpython.console.encoding=UTF-8,详见:http://blog.csdn.net/xfei365/article/details/50955731

总结

虽然在Java中调用Python可以有多种方式解决,甚至因为Jython的出现更显得非常便利。但是这种程序间嵌套调用的方式不可取,首先抛开调用性能不说,增加了耦合复杂度。更加有效的方式应该是通过RCP或者RESTful接口进行解耦,这样各司其职,也便于扩展,良好的架构是一个项目能够健康发展的基础。在微服务架构大行其道的今天,这种程序间嵌套调用的方式将会逐渐被淘汰。

【参考】

http://tonl.iteye.com/blog/1918245 Java调用Python

http://blog.csdn.net/supermig/article/details/24005585 Learning Python -- Java 通过JyThon调用Python实现的规则

http://blog.csdn.net/hpp1314520/article/details/72854011 java 利用Runtime.getRuntime().exec()调用python脚本并传参

http://blog.csdn.net/xingjiarong/article/details/49424253 java调用python方法总结

https://zh.wikipedia.org/wiki/Jython Jython

http://lib.csdn.net/article/python/1654 Jython的安装及简单例子

https://coolshell.cn/articles/2631.html 五大基于JVM的脚本语言

http://python.jobbole.com/82703/ 各种 Python 实现的简单介绍与比较

https://www.oschina.net/translate/why-are-there-so-many-pythons 为什么有这么多 Python?

转载:https://www.cnblogs.com/nuccch/p/8435693.html

推荐内容:
Java 文件流操作.
Java面试知识点之计算机网络篇(一)
Java面试题—初级(7)
十大经典排序算法最强总结(含JAVA代码实现)
JAVA一路走来面试过的问题
java常见面试题
Java面试那些事
java后端面试
面试 10:玩转 Java 选择和插入排序,附冒泡最终源码
税友集团Java开发实习生面试

在Java中调用Python,java面试题,java初级笔试题相关推荐

  1. java中调用python

    在Java中调用Python </h1><div class="clear"></div><div class="postBod ...

  2. 在Java中调用Python

    写在前面 参考:https://www.cnblogs.com/nuccch/p/8435693.html 在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢.当然 ...

  3. java执行python脚本_使用Runtime.getRuntime().exec()在java中调用python脚本

    举例有一个Python脚本叫test.py,现在想要在Java里调用这个脚本.假定这个test.py里面使用了拓展的包,使得pythoninterpreter之类内嵌的编译器无法使用,那么只能采用ja ...

  4. java怎么调用python_如何在Java中调用Python代码

    Jython(原JPython),是一个用2113Java语言写的Python解释5261器.在没有第三方模块的情况下4102,通常选择利用Jython来调用1653Python代码,它是一个开源的J ...

  5. java能调用python吗_如何使用运行时在Java中调用python程序 - java

    我想用来自Java的参数调用python程序.但是我的输出是空白.代码在这里. Python代码在这里: import sys print(sys.argv[1]) Java代码在这里: public ...

  6. Java:在Java中调用python文件执行

    目录 一.Java内置Jpython库(不推荐) 1.1 下载与使用 1.2 缺陷 二.使用Runtime.getRuntime()执行脚本⽂件 2.1 使用 2.2 缺陷 三.利用cmd调用pyth ...

  7. 在Spark Scala/Java应用中调用Python脚本,会么?

    摘要:本文将介绍如何在 Spark scala 程序中调用 Python 脚本,Spark java程序调用的过程也大体相同. 本文分享自华为云社区<[Spark]如何在Spark Scala/ ...

  8. 教你如何在Spark Scala/Java应用中调用Python脚本

    摘要:本文将介绍如何在 Spark scala 程序中调用 Python 脚本,Spark java程序调用的过程也大体相同. 本文分享自华为云社区<[Spark]如何在Spark Scala/ ...

  9. 【Java】-在Java中调用大漠插件

    目录 在Java中调用大漠插件步骤 常见问题 Java与Dll函数的数据通信(一个比较大的坑) 注册了大漠高版本后,如何更换为低版本? Description: 80020010 / 无效的被呼叫方. ...

最新文章

  1. 量子技术新突破!科学家完美实现将单个原子逐一嵌入硅晶片
  2. 封属于旋转轴密封件吗_氧化铝95瓷属于普通型的一种吗?
  3. Spark SQL使用window进行统计
  4. [转]进程,线程和多线程
  5. Linux中的selinux
  6. 蜜罐网络(开源汇总)MHN
  7. 响应式系统的基本原理
  8. linux c 大全,linux c 程序设计大全(吴岳) 求助
  9. 网站站群相关工具001---WebPlus集群平台
  10. Java文件如何用qq邮箱发送_java中怎么发送复杂的邮件?在QQ邮箱中怎么操作?
  11. orm框架有哪些_.net core 基于Dapper 的分库分表开源框架(coredata)
  12. java大数据开发是做什么的_3年Java开发转型大数据,如何跳出CRUD舒适区?
  13. 用C# 设置excel单元格格式
  14. flutter基础布局之 对话框Dialogs
  15. 关于新浪微博开放平台第三方登录接口问题
  16. 清理C盘垃圾文件的方法
  17. Android修真传之工厂模式
  18. 电子发票(PDF)识别信息提取(JAVA)电子专票(OFD)在线预览
  19. 2021-07-12 怎么将桌面图标变大变小
  20. matlab 共振峰检测,基于matlab的语音共振峰的估计.doc

热门文章

  1. 啥叫“Functional Programming ”???
  2. with pdo mysql_如何在PHP下开启PDO MySQL的扩展
  3. (53)多路时钟复用FPGA如何约束二(片内时钟复用约束)
  4. python预测药_python 最麻烦的时间有药了
  5. 文件和内建函数 open() 、file()
  6. c++ 游戏_C/C++编程笔记:C语言实现连连看游戏,项目源码分享
  7. 【其他】学习通下载任务点里的PPT三步走
  8. smb服务器速度测试_通过 SMB 直通优化文件服务器的性能 | Microsoft Docs
  9. STM32H7时钟树RCC分析--- CubeMx配置(三)
  10. nacos 公共_技术分享——使用nacos作注册中心和配置中心