MATLAB 不能从 Java 读回 double[] 数组吗?
考虑 MyClass.java:
public class MyClass {
public void firstfunction(double fwd[]) {
fwd[0] = 42;
}
public void secondfunction(Double fwd[]) {
fwd[0] = new Double(42);
}
}
这两个函数都在 fwd
中返回值 42,对吗?
在 MATLAB 内部,我想访问这个值 42:
myobj=MyClass;
var1=0.0;
myobj.firstfunction(var1);
fprintf('%1.1f',var1); %// ... var1 is still 0.0 ... :-(
var2 = javaArray ('java.lang.Double',1);
var2(1)=java.lang.Double(0.0);
myobj.secondfunction(var2); %// var2 now contains the value 42 :-)
虽然两者都调用“work”(原样:没有错误消息),但只有 var2 包含返回值 42; var1 的值仍然是 0.0。
有没有办法使用 MATLAB 调用函数 firstfunction
并检索返回值?
一些背景: MATLAB 在调用函数时可以传递 Java 对象Java 函数以及对这些对象的修改随后可在 MATLAB 中使用 - 除非当 Java 对象是原始数据类型的数组时。在这种情况下,MATLAB 和 Java 之间的自动转换启动,使 Java 基元双精度数组直接对应于 MATLAB 中的双精度矩阵 - 按照 MATLAB 约定,这是“作为值传递”的事物,因此不可能有返回值。所以我的问题可以改写为有什么办法解决这个问题吗?
(你可以停止阅读这里。)
作为参考,我的特殊情况是这个:
我有一个 Java 类 MyClass.java 包装了一个 DLL,我想在 MATLAB 中使用它。但是,其中一个函数的返回值是作为参数传递的 double[],由于交互方式,其内容不会返回到 MATLAB用Java来实现。
有没有办法解决这个问题,而不修改 DLL 返回数据的方式?
以下是丑陋的细节:
public class MyClass
{
static
{
System.load("C:\\fullpath\\mydll.dll");
}
public static native long SetFWD(double fwd);
public static native long GetFWD(double fwd[]);
}
一旦我正确设置了 javapath,就可以从 MATLAB 中看到这一点:
>> methods MyClass -full
Methods for class MyClass:
static long GetFWD(double[])
MyClass()
static long SetFWD(double)
[and stuff inherited from java.lang.Object]
我可以从 MATLAB 中调用函数 SetFWD,但无法让 GetFWD 返回任何内容:
myobj=MyClass;
fwd=3.0;
myobj.SetFWD(fwdval); % this works fine
fwd=0.0;
myobj.GetFWD(fwd); % this does not give an error, but fwd stays unmodified - as one would expect in MATLAB
fwd = javaArray ('java.lang.Double',1);
fwd(1) = java.lang.Double(0.0);
myobj.GetFWD(fwd) % this gives the error "??? No method 'GetFWD' with matching signature found for class 'MyClass'."
阅读 MATLAB 文档 将数据传递到 Java 方法 和 使用 Java 数组 以及 SO 帖子 从 Java 类型移回 MATLAB 类型 和 从 matlab 传递到 java 的奇怪类,我知道 Matlab 会自动将我传递给函数的任何双精度数组转换为 Java 数组,然后忽略这些数组中所做的任何修改。看来,如果 MyClass 中的函数定义包含 Double 对象而不是 double 基元,那么我的第二次尝试就可以工作。
有没有办法让 MATLAB 返回我想要的值,而不修改原始的 .DLL (mydll.dll)?
更新
据我了解,MATLAB 通常“按值”传递所有内容。但在 将数据传递给 Java 方法 Mathworks 中说
如果您需要访问更改 Java 方法创建一个数组,然后, 而不是传递 MATLAB 数组, 你应该创建并传递一个Java 数组,这是一个引用。
他们在 使用 Java 数组 如何使用 javaArray 函数做到这一点,但我无法让它用于创建数组 double[] (即原始双精度数组),仅适用于 Double[] (即 Double 对象数组),即不是我在这里需要的,因为我的函数 GetFWD() 不吃后者:-(。
>> A=javaArray ('java.lang.double',1); % works fine, but cannot be used as parameter for my function GetFWD (see "No Method ... with matching signature..." error above)
>> A=javaArray ('double',1);
??? Error using ==> javaArray
No class double can be located on the MATLAB Java classpath
Consider MyClass.java:
public class MyClass {
public void firstfunction(double fwd[]) {
fwd[0] = 42;
}
public void secondfunction(Double fwd[]) {
fwd[0] = new Double(42);
}
}
Both functions return the value 42 in fwd
, right?
From within MATLAB, I want to access this value 42:
myobj=MyClass;
var1=0.0;
myobj.firstfunction(var1);
fprintf('%1.1f',var1); %// ... var1 is still 0.0 ... :-(
var2 = javaArray ('java.lang.Double',1);
var2(1)=java.lang.Double(0.0);
myobj.secondfunction(var2); %// var2 now contains the value 42 :-)
While both calls "work" (as is: no error message), only var2 contains the return value 42; var1 still has the value 0.0.
Is there any way to use MATLAB to call the function firstfunction
and retrieve the return value?
Some background: MATLAB can pass Java objects when calling a Java function, and modifications to these objects are afterwards available in MATLAB - except when the Java object is an array of a primitive data type. In this case automatic conversion between MATLAB and Java kicks in, making a Java array-of-primitive-double correspond directly to a double matrix in MATLAB - which is by MATLAB conventions a thing "passed as value" so no return values are possible. So my question can be rephrased as is there any way around this?
(you can stop reading here.)
For reference, my special case was this:
I have a Java class MyClass.java wrapping a DLL, which I want to use in MATLAB. However, the return value of one of the functions is a double[] passed as a parameter, the content of which doesn't make it back to MATLAB due to how interaction with Java is implemented.
Is there any way around this problem, without modifying the way the DLL returns the data?
Here are the ugly details:
public class MyClass
{
static
{
System.load("C:\\fullpath\\mydll.dll");
}
public static native long SetFWD(double fwd);
public static native long GetFWD(double fwd[]);
}
This is visible from within MATLAB once I set the javapath correctly:
>> methods MyClass -full
Methods for class MyClass:
static long GetFWD(double[])
MyClass()
static long SetFWD(double)
[and stuff inherited from java.lang.Object]
I can call the function SetFWD from within MATLAB, but I can't get GetFWD to return anything:
myobj=MyClass;
fwd=3.0;
myobj.SetFWD(fwdval); % this works fine
fwd=0.0;
myobj.GetFWD(fwd); % this does not give an error, but fwd stays unmodified - as one would expect in MATLAB
fwd = javaArray ('java.lang.Double',1);
fwd(1) = java.lang.Double(0.0);
myobj.GetFWD(fwd) % this gives the error "??? No method 'GetFWD' with matching signature found for class 'MyClass'."
From reading MATLAB Documentation Passing Data to a Java Method and Working with Java Arrays as well as SO posts Moving from Java types back to MATLAB types and Strange classes passed from matlab to java, I understand that Matlab automagically converts any double array that I pass to the function into a Java array, and then ignores whatever modifications does in these arrays. It seems that if my function definition in MyClass contained Double objects instead of double primitives, my second attempt could work.
Is there any way to get MATLAB to return the value I'm after, without modifying the original .DLL (mydll.dll)?
Update
I understand that MATLAB usually passes everything "by value". But in Passing Data to a Java Method Mathworks say that
If you need to access changes that a
Java method makes to an array, then,
rather than passing a MATLAB array,
you should create and pass a Java
array, which is a reference.
They explain in Working with Java Arrays how to do that using the javaArray function, but I couldn't get this to work for creating an array double[] (i.e. an array of primitive doubles), only for Double[] (i.e. an array of Double objects) which is not what I need here, since my function GetFWD() doesn't eat the latter :-(.
>> A=javaArray ('java.lang.double',1); % works fine, but cannot be used as parameter for my function GetFWD (see "No Method ... with matching signature..." error above)
>> A=javaArray ('double',1);
??? Error using ==> javaArray
No class double can be located on the MATLAB Java classpath
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不,不能。
我找到了这个解决方法,我可以接受:虽然我(我自己)无法修改 DLL,但我可以在 java 类 MyClass 中添加一个包装函数,像这样:
这个包装函数有一个 Double 对象数组作为参数,我可以像这样从 MATLAB 访问它:
所以这回答了我对问题的解决方法的问题,因为它不涉及更改 DLL 的接口(仅 Java 类的接口)。
然而,标题中更基本的问题仍然没有答案:在 MATLAB 中是否真的不可能将 array-of-primitive-double 的引用传递给 Java 函数,从而绕过 Matlab 的自动转换-double-array 到 Java-primitive-double-array 并返回,这似乎使得无法访问 Java 代码对此类数组所做的任何更改。
No, it can not.
I have found this workaround, that I can live with: while I can't (myself) modify the DLL, I can add a wrapper function in the java class MyClass, like so:
This wrapper function has an array of Double objects as a parameter, which I can access from MATLAB like this:
So this answers my question for a workaround to the problem, since it doesn't involve changing the interface of the DLL (only the interface of the Java Class).
However, the more fundamental question in the title is still unanswered: Is it really impossible in MATLAB to pass a reference to an array-of-primitive-double to a Java function, circumventing the automatic conversion of Matlab-double-array to Java-primitive-double-array and back which seems to make it impossible to access any changes the Java code made to such an array.
这不是一个错误,它是预期的行为
firstfunction
接受原始双精度数组的副本,修改该副本并返回,而不更改任何内容MyClass
实例。secondfunction
获取对java.lang.Double
数组的引用作为输入 - 因此 MATLAB 可以看到对该数组所做的任何更改。在 Java 代码中,您可以传递对双精度数组的引用,但当它们作为 MATLAB 的输出或输入提供时,它们将始终作为副本传递。
您可能会找到类似 Apache Math 的包装器
ArrayRealVector
有所帮助,但即使如此,从 MATLAB 访问底层数组也会创建一个副本 - 即使调用getDataRef
时也是如此,因为 Apache Math 将返回一个引用,但 MATLAB 会然后复制它。不过,您可以调用 ArrayRealVectorsetEntry
和getEntry
方法从 MATLAB 修改底层双精度数组。This is not a bug, it is expected behaviour
firstfunction
accepts a copy of a primitive double array, modifies that copy and returns without altering anything in theMyClass
instance.secondfunction
gets a reference to ajava.lang.Double
array as input - so MATLAB sees any changes made to that array.Within Java code, you can pass references to double arrays but they will always be passed as copies when provided as output or input from MATLAB.
You might find a wrapper like the Apache Math
ArrayRealVector
helps but even there, accessing the underlying array from MATLAB will create a copy - even when callinggetDataRef
, as Apache Math will return a reference but MATLAB will then copy it. You can though call the ArrayRealVectorsetEntry
andgetEntry
methods to modify the underlying double array from MATLAB.尝试在 Matlab 元胞数组中传递数值,例如:
myobj.GetFWD({1.2, 3.4, 5.6});
或者甚至可能是常规 Matlab 数组:
myobj.GetFWD([ 1.2、3.4、5.6]);
Try to pass the numerical values within a Matlab cell array, e.g.:
myobj.GetFWD({1.2, 3.4, 5.6});
or maybe even a regular Matlab array:
myobj.GetFWD([1.2, 3.4, 5.6]);