When you invoke a method on a generated class, the input arguments received by the method must be in the MATLAB® internal array format. You can either convert them yourself within the calling program, or pass the arguments as Java® data types, which are then automatically converted by the calling mechanism.
To convert them yourself, use instances of the MWArray
classes;
in this case you are using manual conversion.
Storing your data using the classes and data types defined in the Java language
means that you are relying on automatic conversion.
Most likely, you will use a combination of manual and automatic conversion.
To manually convert to one of the standard MATLAB data
types, use the MWArray
data conversion classes
provided by the compiler. For class reference and usage information,
see the com.mathworks.toolbox.javabuilder
package.
The Magic Square example (Integrate a Java Package into an Application)
exemplifies manual conversion. The following code fragment from that
program shows a java.lang.Double
argument that
is converted to an MWNumericArray
type that can
be used by the MATLAB function without further conversion:
n = new MWNumericArray(Double.valueOf(args[0]), MWClassID.DOUBLE); theMagic = new Class1(); result = theMagic.makesqr(1, n);
Passing an MWArray. This example constructs an MWNumericArray
of
type MWClassID.DOUBLE
. The call to myprimes
passes
the number of outputs, 1
, and the MWNumericArray
, x
:
x = new MWNumericArray(n, MWClassID.DOUBLE); cls = new myclass(); y = cls.myprimes(1, x);
The Java bridge converts the MWNumericArray
object
to a MATLAB scalar double
to pass to the MATLAB function.
When passing an argument only a small number of times, it is usually just as efficient to pass a primitive Java type or object. In this case, the calling mechanism converts the data for you into an equivalent MATLAB type.
For instance, either of the following Java types would
be automatically converted to the MATLAB double
type:
A Java double
primitive
An object of class java.lang.Double
For reference information about data conversion (tables showing each Java type along with its converted MATLAB type, and each MATLAB type with its converted Java type), see Data Conversion Rules.
When calling the makesqr
method used in the getmagic
application,
you could construct an object of type MWNumericArray
.
Doing so would be an example of manual conversion. Instead, you could
rely on automatic conversion, as shown in the following code fragment:
result = M.makesqr(1, arg[0]);
In this case, a Java double
is passed
as arg[0]
.
Here is another example:
result = theFourier.plotfft(3, data, new Double(interval));
In this Java statement, the third argument is of type java.lang.Double
.
According to conversion rules, the java.lang.Double
automatically
converts to a MATLAB 1-by-1 double
array.
The example calls the myprimes
method with
two arguments. The first specifies the number of arguments to return.
The second is an object of class java.lang.Double
that
passes the one data input to myprimes
.
cls = new myclass(); y = cls.myprimes(1, new Double((double)n));
This second argument is converted to a MATLAB 1-by-1 double
array,
as required by the MATLAB function. This is the default conversion
rule for java.lang.Double
.
This example constructs an MWNumericArray
of
type MWClassID.DOUBLE
. The call to myprimes
passes
the number of outputs, 1
, and the MWNumericArray
, x
.
x = new MWNumericArray(n, MWClassID.DOUBLE); cls = new myclass(); y = cls.myprimes(1, x);
The compiler converts the MWNumericArray
object
to a MATLAB scalar double
to pass to the MATLAB function.
The conversion rules apply not only when calling your own methods,
but also when calling constructors and factory methods belonging to
the MWArray
classes.
For example, the following code fragment calls the constructor
for the MWNumericArray
class with a Java double
as
the input argument:
double Adata = 24; MWNumericArray A = new MWnumericArray(Adata); System.out.println("Array A is of type " + A.classID());
The compiler converts the input argument to an instance of MWNumericArray
,
with a ClassID
property of MWClassID.DOUBLE
.
This MWNumericArray
object is the equivalent of
a MATLAB 1-by-1 double
array.
When you run this example, the result is as follows:
Array A is of type double
When calling an MWArray
class method constructor,
supplying a specific data type causes the MATLAB Compiler SDK™ product
to convert to that type instead of the default.
For example, in the following code fragment, the code specifies
that A
should be constructed as a MATLAB 1-by-1
16-bit integer array:
double Adata = 24; MWNumericArray A = new MWnumericArray(Adata, MWClassID.INT16); System.out.println("Array A is of type " + A.classID());
When you run this example, the result is as follows:
Array A is of type int16
So far, the examples have not used MATLAB functions that
have varargin
or varargout
arguments.
Consider the following MATLAB function:
function y = mysum(varargin) y = sum([varargin{:}]);
This function returns the sum of the inputs. The inputs are
provided as a varargin
argument, which means that
the caller can specify any number of inputs to the function. The result
is returned as a scalar double
.
The MATLAB Compiler SDK product generates a Java interface to this function as follows:
/* mlx interface - List version*/ public void mysum(List lhs, List rhs) throws MWException { (implementation omitted) } /* mlx interface - Array version*/ public void mysum(Object[] lhs, Object[] rhs) throws MWException { (implementation omitted) } /* standard interface - no inputs */ public Object[] mysum(int nargout) throws MWException { (implementation omitted) } /* standard interface - variable inputs */ public Object[] mysum(int nargout, Object varargin) throws MWException { (implementation omitted) }
In all cases, the varargin
argument is passed
as type Object
. This lets you provide any number
of inputs in the form of an array of Object, that is Object[]
,
and the contents of this array are passed to the compiled MATLAB function
in the order in which they appear in the array. Here is an example
of how you might use the mysum
method in a Java program:
public double getsum(double[] vals) throws MWException { myclass cls = null; Object[] x = {vals}; Object[] y = null; try { cls = new myclass(); y = cls.mysum(1, x); return ((MWNumericArray)y[0]).getDouble(1); } finally { MWArray.disposeArray(y); if (cls != null) cls.dispose(); } }
In this example, an Object
array of length
1 is created and initialized with a reference to the supplied double
array.
This argument is passed to the mysum
method. The
result is known to be a scalar double
, so the code
returns this double
value with the statement:
return ((MWNumericArray)y[0]).getDouble(1);
Cast the return value to MWNumericArray
and
invoke the getDouble(int)
method to return the
first element in the array as a primitive double
value.
Pass Array Inputs. The next example performs a more general calculation:
public double getsum(Object[] vals) throws MWException { myclass cls = null; Object[] x = null; Object[] y = null; try { x = new Object[vals.length]; for (int i = 0; i < vals.length; i++) x[i] = new MWNumericArray(vals[i], MWClassID.DOUBLE); cls = new myclass(); y = cls.mysum(1, x); return ((MWNumericArray)y[0]).getDouble(1); } finally { MWArray.disposeArray(x); MWArray.disposeArray(y); if (cls != null) cls.dispose(); } }
This version of getsum
takes an array of Object
as
input and converts each value to a double
array.
The list of double
arrays is then passed to the mysum
function,
where it calculates the total sum of each input array.
When present, varargout
arguments are handled
in the same way that varargin
arguments are handled.
Consider the following MATLAB function:
function varargout = randvectors for i=1:nargout varargout{i} = rand(1, i); end
This function returns a list of random double
vectors
such that the length of the i
th vector is equal
to i
. The MATLAB Compiler™ product generates
a Java interface to this function as follows:
/* mlx interface - List version */ public void randvectors(List lhs, List rhs) throws MWException { (implementation omitted) } /* mlx interface - Array version */ public void randvectors(Object[] lhs, Object[] rhs) throws MWException { (implementation omitted) } /* Standard interface - no inputs*/ public Object[] randvectors(int nargout) throws MWException { (implementation omitted) }
Pass Optional Arguments with the Standard Interface. Here is one way to use the randvectors
method
in a Java program:
public double[][] getrandvectors(int n) throws MWException { myclass cls = null; Object[] y = null; try { cls = new myclass(); y = cls.randvectors(n); double[][] ret = new double[y.length][]; for (int i = 0; i < y.length; i++) ret[i] = (double[])((MWArray)y[i]).getData(); return ret; } finally { MWArray.disposeArray(y); if (cls != null) cls.dispose(); } }
The getrandvectors
method returns a two-dimensional double
array
with a triangular structure. The length of the i
th
row equals i
. Such arrays are commonly referred
to as jagged arrays. Jagged arrays are easily
supported in Java because a Java matrix is just an array
of arrays.
The previous examples used the fact that you knew the type and dimensionality of the output argument. In the case that this information is unknown, or can vary (as is possible in MATLAB programming), the code that calls the method might need to query the type and dimensionality of the output arguments.
There are several ways to do this. Do one of the following:
Use reflection support in the Java language to query any object for its type.
Use several methods provided by the MWArray
class
to query information about the underlying MATLAB array.
Coercing to a specific type using the to
Type
Array
methods.
This code sample calls the myprimes
method,
and then determines the type using reflection. The example assumes
that the output is returned as a numeric matrix but the exact numeric
type is unknown.
public void getprimes(int n) throws MWException { myclass cls = null; Object[] y = null; try { cls = new myclass(); y = cls.myprimes(1, new Double((double)n)); Object a = ((MWArray)y[0]).toArray(); if (a instanceof double[][]) { double[][] x = (double[][])a; /* (do something with x...) */ } else if (a instanceof float[][]) { float[][] x = (float[][])a; /* (do something with x...) */ } else if (a instanceof int[][]) { int[][] x = (int[][])a; /* (do something with x...) */ } else if (a instanceof long[][]) { long[][] x = (long[][])a; /* (do something with x...) */ } else if (a instanceof short[][]) { short[][] x = (short[][])a; /* (do something with x...) */ } else if (a instanceof byte[][]) { byte[][] x = (byte[][])a; /* (do something with x...) */ } else { throw new MWException( "Bad type returned from myprimes"); } }
This example uses the toArray
method to return
a Java primitive array representing the underlying MATLAB array.
The toArray
method works just like getData
in
the previous examples, except that the returned array has the same
dimensionality as the underlying MATLAB array.
The next example uses the MWArray
classID
method
to determine the type of the underlying MATLAB array. It also
checks the dimensionality by calling numberOfDimensions
.
If any unexpected information is returned, an exception is thrown.
It then checks the MWClassID
and processes the
array accordingly.
public void getprimes(int n) throws MWException { myclass cls = null; Object[] y = null; try { cls = new myclass(); y = cls.myprimes(1, new Double((double)n)); MWClassID clsid = ((MWArray)y[0]).classID(); if (!clsid.isNumeric() || ((MWArray)y[0]).numberOfDimensions() != 2) { throw new MWException("Bad type returned from myprimes"); } if (clsid == MWClassID.DOUBLE) { double[][] x = (double[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } else if (clsid == MWClassID.SINGLE) { float[][] x = (float[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } else if (clsid == MWClassID.INT32 || clsid == MWClassID.UINT32) { int[][] x = (int[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } else if (clsid == MWClassID.INT64 || clsid == MWClassID.UINT64) { long[][] x = (long[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } else if (clsid == MWClassID.INT16 || clsid == MWClassID.UINT16) { short[][] x = (short[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } else if (clsid == MWClassID.INT8 || clsid == MWClassID.UINT8) { byte[][] x = (byte[][])((MWArray)y[0]).toArray(); /* (do something with x...) */ } } finally { MWArray.disposeArray(y); if (cls != null) cls.dispose(); } }
The next example demonstrates how you can coerce or force data
to a specified numeric type by invoking any of the toType
Array
methods. These methods return an array of Java types matching
the primitive type specified in the name of the called method. The
data is coerced or forced to the primitive type specified in the method
name. Note that when using these methods, data will be truncated when
needed to allow conformance to the specified data type.
Object results = null; try { // call a compiled MATLAB function results = myobject.myfunction(2); // first output is known to be a numeric matrix MWArray resultA = (MWNumericArray) results[0]; double[][] a = (double[][]) resultA.toDoubleArray(); // second output is known to be // a 3-dimensional numeric array MWArray resultB = (MWNumericArray) results[1]; Int[][][] b = (Int[][][]) resultB.toIntArray(); } finally { MWArray.disposeArray(results); }