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

Matlab/Octave中使用Java

2016-08-14 18:48 260 查看
Matlab对于混合编程提供了广泛的支持,例如,Matlab通过mex编程方式可以调用Fortran或者C语言编写的mex文件;而通过mcc可以将Matlab的m文件编译为可被C/C++调用的动态链接库或者独立的可执行文件。此外,Matlab还提供了对Java、COM、.net以及excel等的支持,可以实现各种具有创意的混合编程形式。通过Matlab和Java混合编程,可以实现在Matlab中调用用户自定义的jar,或者在Java程序中调用Matlab代码。

本文就来谈谈在Matlab中调用Java的相关话题。由于Octave可以视作Matlab的开源替代品,大多数Matlab代码也可以几乎不做改变地在octave中运行,所以本文中将Octave和Matlab相提并论。为了保证二者之间的可移植性,本文只讨论对二者都适用的话题。

Matlab/Octave中都提供对以下两个函数的支持:

javaObject

javaMethod

javaObject
用于生成Java对象,而
javaMethod
可以调用Java对象的方法。

利用这两个方法,可以在Matlab/Octave中轻松调用Java代码,由于Java含有丰富的第三方库,从而可以极大扩展Matlab的功能。例如,利用Java进行更加高级的GUI设计,Java调用zxing识别二维码或者在Matlab/Octave中调用利用Java开发的科学应用程序(举个例子,现在很多大数据应用程序都是利用Java/Scala这类语言开发,发布时打包为一个jar包,提交到Hadoop/Spark集群上运行。利用Matlab对Java的支持,我们可以基于Matlab平台配置一个Hadoop应用程序的测试环境。即,利用Java开发算法核心算法代码并打包,在Matlab中调用jar包运行。运算前后也可以在Matlab进行一些预处理(数据格式变换等等)或者后处理(画图,生成报告等),这样可以充分发挥二者在各自领域的优势)。

1. Java类导入到Matlab Workspace

为了正确导入Java类,首先需要在Matlab中正确配置Java的classpath。主要有以下几种方式:

添加到静态classpath

在Matlab命令行中输入
edit classapth.txt
,将用户自定义的
classpath
路径添加到文件末尾。

添加到
java.ext.path
目录

执行
java.lang.System.getProperty('java.ext.dirs')
命令获取Java扩展目录。将用户自己的jar包到ext目录中。

使用动态classpath

Matlab提供了
javaclasspath
javaaddapth
javarmpath
等命令来动态配置Java的classpath。

前两种方式需要重启Matlab才能生效,而第三种方法可以立即生效。如果只是为了测试,建议使用动态classpath方式。因为前两种方式都会修改Matlab的默认配置,而为了系统的安全,最好只对其做最小的修改。

通过
javaclasspath('dynamic')
javaclasspath('static')
可以查Java classpath的当前配置。

接下来就可以使用
import
命令将Java类导入到Matlab工作空间:

import java.util.Date
import org.apache.log4j.Logger


若输入
import
,不加其他参数,则查看当前所有导入的Java类,利用
clear import
清除导入的Java类。

使用
[mObj, mexObj, javaObj] = inmem()
还可以查看内存中当前已有的Java对象,即
javaObj
中的内容,而
clear java
清除内存中的Java对象。

2. 查看Java类的相关信息

查看Java类的方法

methods java.util.Date -full
methodsview java.util.Date


查看Java类的字段

fieldnames(java.util.Date)


3. Matlab中使用Java对象

首先创建一个Java对象:

dateObj = java.util.Date()


或者使用:

dateObj = javaObject('java.util.Date')


查看Java对象类型:

class(dateObj)
isjava(dateObj)


调用Java对象的方法,有以下3种形式:

dateObj.toString()
toString(dateObj)
javaMethod('toString', dateObj)


关于以上涉及的各个Matlab命令的详细说明参考Matlab帮助文档,例如

doc javaObject
doc javaMethod


4. 实例1:利用Java Swing实现高级GUI

下面我们来看一个利用Java Swing实现高级GUI的例子。程序利用Java Swing的Frame显示一个无边框图片窗口,3秒后窗口关闭。这可以很容易应用到程序的启动动画中。例如,Matlab启动时显示的spalash就可以这样实现。代码如下:

ImageFile  = 'ngc6543a.jpg';
ScreenSize = get(0, 'ScreenSize');
jImage     = im2java(imread(ImageFile));
jfBounds   = num2cell([...
(ScreenSize(3)-jImage.getWidth)/2 ...
(ScreenSize(4)-jImage.getHeight)/2 ...
jImage.getWidth ...
jImage.getHeight]);

jFrame     = javax.swing.JFrame;
icon       = javax.swing.ImageIcon(jImage);
label      = javax.swing.JLabel(icon);
jFrame.getContentPane.add(label);
jFrame.setUndecorated(true)
jFrame.setBounds(jfBounds{:});
jFrame.pack
jFrame.show
pause(3)
jFrame.dispose


5. 实例2:用户自定义Java类的调用

以上例子演示的是在Matlab中调用Java标准类,几乎没有什么难度,也不会出现什么问题。然而,当尝试在Matlab中调用用户自定义的Java类时,情况往往就不是那么简单了。

为了测试,我们创建一个简单的Java类
abc.Point


// Point.java
package abc;

public class Point {
double x;
double y;

public Point(double x, double y) {
this.x = x;
this.y = y;
}

public void setX(double x) {
this.x = x;
}

public void setY(double y) {
this.y = y;
}

public double getX() {
return this.x;
}

public double getY() {
return this.y;
}

public String toString() {
return "(" + x + "," + y +")";
}

public void display() {
System.out.println("Coordinate: " + toString());
}

public static void main(String args[]) {
new Point(1,2).display();
}
}


接下来我们将其打包,生成point.jar文件。

最简单的是使用Eclipse编译并打包。由于此处只有一个Java文件,我们选择直接在命令行下完成文件的编译和打包。

首先编译
Point.java
:

javac -d . -s . Point.java


这会在当前目录自动生成abc文件夹,里面是Point.class文件。

我们可以先测试一下
Point.class
,执行
java abc.Point
,输出
Coordinate: (1.0,2.0)
,正常。

再利用jar命令打包:

jar -cvf point.jar -C . abc Point.java


其中
-C . abc Point.java
表示将当前目录下的abc文件夹和Point.java文件打包到待生成的point.jar文件中。

接下来将point.jar复制到Matlab环境中进行测试:

base  = pwd
ext   = {[base], [base '/point.jar']};
javaaddpath(ext)

import abc.Point


很不幸,在执行
import abc.Point
时会报错,Matlab提示找不到
abc.Point
类。而通过·
javaclasspath
命令查看当前的javaclasspath配置,却发现当前目录以及point.jar确实已经加入了j动态avaclasspath路径中。

而且执行
import abc.*
也是正常的,不会报错。而如果将point.jar复制到Java ext目录中,执行
import abc.Point
时会抛出异常
java.lang.UnsupportedClassVersionError


这其实就是执行
import abc.*
失败的真正原因,因为用户自定义jar包中的class文件和Matlab的jre版本不兼容,导致Matlab的jre无法加载用户jar包中的class文件。具体来说,Matlab中的jre版本比较老(我的Matlab是R2010,jre版本为1.5),而我编译Java代码以及打包使用的JDK是1.7的。关于JDK版本兼容的话题,可以参考这篇帖子

这一问题是大多数尝试在Matlab中调用Java的人都会遇到的一个问题,因此这里特别提出来进行说明。

下面说一下怎么解决。其实思路很简单,既然是JDK版本不兼容问题,那当然是采用兼容的版本了。

如果使用Eclipse编译和打包,设定compiler时选择版本1.5。而如果使用命令行的方式编译和打包,则需要通过
javac
-target
选项指定生成的class文件的版本,这里为了保证兼容性,选择1.5。对应的命令为:

javac -d . -s . -source 1.5 -target 1.5 Point.java
jar -cvf point.jar -C . abc Point.java


之后再将生成的jar包放到Matlab中进行测试,发现此时
abc.Point
可以正常导入了。

最后,附上测试用的Matlab代码:

% MatlabCallJavaDemo.m

base  = fileparts(mfilename('fullpath'));
exts  = {[base], [base '/point.jar']};

% Add this path to java dynamic classpath
javaclasspath(exts)

% alternatively, the following statement is also OK
% javaaddpath(ext)

% show java dynamic classpath
javaclasspath('-dynamic')

%% Test case 1: import class
import('abc.Point')
import

% show methods of abc.Point class
methods abc.Point
methods('abc.Point', '-full')
methodsview('abc.Point')

point = Point(1, 2)

%% Test case 2: create java object and invoke methods
point = abc.Point(1, 2);
x = point.getX()
y = getY(point)

%% Test case 2: create java object and invoke methods using javaObject and javaMethod
point = javaObject('abc.Point', 1, 2)
javaMethod('display', point)
x = javaMethod('getX', point)
y = javaMethod('getY', point)

% alternatively. you can remove the exts from javaclasspath
clear point
for i = 1:numel(exts)
javarmpath(exts{i})
end


完整代码可以从CSDN下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matlab java