主要内容

本页采用了机器翻译。点击此处可查看最新英文版本。

在 MATLAB 中编组 Java 结构 (Structs)

R2026a

结构(或 structs)是 MATLAB® 数组,其元素通过文本字段指示符访问。

结构由称为字段的数据容器组成。每个字段存储某种 MATLAB 数据类型的数组。每个字段都有一个唯一的名称。

结构体中的字段可以具有与任何 MATLAB 数据类型兼容的值,包括元胞数组或其他结构体。

在 MATLAB 中,创建一个结构体如下:

S.name = 'Ed Plum';
S.score = 83;
S.grade = 'B+' 
此代码创建一个具有三个字段的标量结构体 (S):
S = 
    name: 'Ed Plum'
    score: 83
    grade: 'B+'
可以通过插入附加元素来创建多维结构体数组:
S(2).name = 'Toni Miller';
S(2).score = 91;
S(2).grade = 'A-';
在这种情况下,将创建一个维度为 (1,2) 的结构体数组。还支持具有附加维度的结构。

由于 Java® 本身不支持 MATLAB 结构体,服务器和客户端之间的编组结构体需要额外的编码。

在客户端和服务器之间编组结构

MATLAB 结构体是名称-值对的有序列表。您可以使用由相同区分大小写的名称组成的字段在 Java 中表示它们。

Java 类还必须为每个字段定义 public get 和 set 方法。该类是否同时需要 get 和 set 方法取决于它是用作输入还是输出,或者两者兼而有之。

下面是一个简单示例,说明如何在 MATLAB 客户端和服务器之间编组 Java 结构体。

在这个示例中,MATLAB 函数 sortstudents 接受一个结构体数组(详情请参阅 在 MATLAB 中编组 Java 结构 (Structs))。

结构体数组中的每个元素代表学生的不同信息。sortstudents 按每个学生的分数对输入数组进行升序排序,如下所示:

function sorted = sortstudents(unsorted)
% Receive a vector of students as input
% Get scores of all the students
scores = {unsorted.score};
% Convert the cell array containing scores into a numeric array or doubles
scores = cell2mat(scores);
% Sort the scores array
[s i] = sort(scores);
% Sort the students array based on the sorted scores array
sorted = unsorted(i);

注意

尽管此示例仅使用输入结构体的 scores 字段,但您也可以以类似的方式使用 name 和 grade 字段。

您使用 Production Server Compiler 将 sortstudents 打包成可部署存档(scoresorter.ctf)(详情请参阅 针对 MATLAB Production Server 创建可部署存档),并使其在服务器 http://localhost:9910/scoresorter 上可用,以供 Java 客户端访问(请参阅 将存档部署至 MATLAB Production Server)。

在定义客户端所需的 Java 接口之前,使用 MATLAB 类定义 Java 结构体 Student。

Student 用适当的类型声明字段 name、score 和 grade。它还包含 public get 和 set 函数来访问这些字段。

public class Student{

    private String name;
    private int score;
    private String grade;
    
    public Student(){
    }
    
    public Student(String name, int score, String grade){
        this.name = name;
        this.score = score;
        this.grade = grade;
    }

    public String getName(){
        return name;    
    }
    
    public void setName(String name){
        this.name = name;
    }
    
    public int getScore(){
        return score;    
    }
    
    public void setScore(int score){
        this.score = score;
    }
    
    public String getGrade(){
        return grade;    
    }
    
    public void setGrade(String grade){
        this.grade = grade;
    }
    
    public String toString(){
        return "Student:\n\tname : " + name + 
               "\n\tscore : " + score + "\n\tgrade : " + grade;
    }   
}

注意

请注意,此示例使用了 toString 方法以方便编组。这不是必需的。

接下来,定义 Java 接口 StudentSorter,它调用方法 sortstudents 并使用 Student 类来编组输入和输出。

由于您正在使用结构类型,因此 Student 必须包含在注解 MWStructureList 中。

interface StudentSorter {
    @MWStructureList({Student.class})
    Student[] sortstudents(Student[] students) 
            throws IOException, MATLABException;
}

最后,为客户端编写 Java 应用程序 (MPSClientExample):

  1. 创建 MWHttpClient 和相关代理(使用 createProxy),如使用 MWHttpClient 类创建 MATLABProduction ServerJava 客户端所示。

  2. 在 Java 中创建一个未排序的学生结构体数组,其命名、输入和输出数量以及 MATLAB 中的类型有效性模仿 MATLAB 结构。有关详细信息,请参阅Java 客户端编码最佳实践。

  3. 对学生数组进行排序并显示。

import java.net.URL;
import java.io.IOException;
import com.mathworks.mps.client.MWClient;
import com.mathworks.mps.client.MWHttpClient;
import com.mathworks.mps.client.MATLABException;
import com.mathworks.mps.client.annotations.MWStructureList;

interface StudentSorter {
    @MWStructureList({Student.class})
    Student[] sortstudents(Student[] students) 
            throws IOException, MATLABException;
}

public class ClientExample {

    public static void main(String[] args){
    
        MWClient client = new MWHttpClient();
        try{
            StudentSorter s = 
               client.createProxy(new URL("http://localhost:9910/scoresorter"), 
                                                          StudentSorter.class );
            Student[] students = new Student[]{new Student("Toni Miller", 90, "A"), 
                                               new Student("Ed Plum",     80, "B+"),
                                               new Student("Mark Jones",  85, "A-")};
            Student[] sorted = s.sortstudents(students);
            System.out.println("Student list sorted in the 
                            ascending order of scores : ");
            for(Student st:sorted){
                System.out.println(st);
            }
        }catch(IOException ex){
            System.out.println(ex);
        }catch(MATLABException ex){
            System.out.println(ex);
        }finally{
            client.close();        
        }
    }
}

将 Java 字段名称映射到 MATLAB 字段名称

表示 Java 结构体的 MATLAB 类使用 Java Beans Introspector 类 (https://docs.oracle.com/javase/6/docs/api/java/beans/Introspector.html) 将属性映射到字段,并使用其默认命名约定。

这意味着默认使用其 decapitalize() 方法。这将 Java 字段的首字母映射为小写字母。默认情况下,无法定义一个 Java 字段来映射到以大写字母开头的 MATLAB 字段。

您可以通过使用自定义 BeanInfo 方法实现 getPropertyDescriptors() 类来覆盖此行为。例如:

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.SimpleBeanInfo;
public class StudentBeanInfo extends SimpleBeanInfo
{
  @Override
  public PropertyDescriptor[] getPropertyDescriptors()
  {
  PropertyDescriptor[] props = new  PropertyDescriptor[3];
  try
  {
    // name uses default naming conventions so we do not need to
    // explicitly specify the accessor names.
    props[0] = new PropertyDescriptor("name",MyStruct.class);
    // score uses default naming conventions so we do not need to
    // explicitly specify the accessor names.
    props[1] = new PropertyDescriptor("score",MyStruct.class);
    // Grade uses a custom naming convention so we do need to
    // explicitly specify the accessor names.
    props[1] = new PropertyDescriptor("Grade",MyStruct.class,
                                      "getGrade","setGrade");
    return props;
  }
  catch (IntrospectionException e)
  {
    e.printStackTrace();
  }
  
  return null;
  }
}

定义仅用作输入的 MATLAB 结构

将 Java 结构定义为输入时,请遵循以下准则:

  • 确保 Java 类中的字段与 MATLAB 结构中的字段名称完全匹配。字段名称区分大小写。

  • 在 Java 类中的字段上使用 public get 方法。该类是否需要字段的 get 和 set 方法取决于它是用作输入还是输出,或者两者兼而有之。在此示例中,请注意,当 student 作为输入传递给方法 sortstudents 时,数据编组算法仅使用其字段的 get 方法。

因此,如果为仅用作输入值的 Java 结构体定义了 MATLAB 类,则不需要 set 方法。此版本的 Student 类仅代表输入值:

public class Student{

    private String name;
    private int score;
    private String grade;
    
    public Student(String name, int score, String grade){
        this.name = name;
        this.score = score;
        this.grade = grade;
    }

    public String getName(){
        return name;    
    }
    
    public int getScore(){
        return score;    
    }
    
    public String getGrade(){
        return grade;    
    }  
}

定义仅用作输出的 MATLAB 结构

将 Java 结构定义为输出时,请遵循以下准则:

  • 确保 Java 类中的字段与 MATLAB 结构中的字段名称完全匹配。字段名称区分大小写。

  • 使用从 Java 接收的结构体创建 MATLAB 类的新实例。通过使用 set 方法或 Java 提供的 @ConstructorProperties 注解来实现。在定义仅输出的 Java 结构体时,MATLAB 类不需要 get 方法。

使用 Student 方法的仅输出 set 类如下:

public class Student{

    private String name;
    private int score;
    private String grade;    
    
    public void setName(String name){
        this.name = name;
    }
    
    public void setScore(int score){
        this.score = score;
    }    
    
    public void setGrade(String grade){
        this.grade = grade;
    }
}

使用 Student 的仅输出 @ConstructorProperties 类如下:

public class Student{

    private String name;
    private int score;
    private String grade;    
    
    @ConstructorProperties({"name","score","grade"})
    public Student(String n, int s, String g){
        this.name = n;
        this.score = s;
        this.grade = g;
    }    
}

注意

如果同时提供了 set 方法和 @ConstructorProperties 注解,则 set 方法优先于 @ConstructorProperties 注解。

定义用作输入和输出的 MATLAB 结构

如果 Student 类同时用作输入和输出,则需要提供 get 方法来执行对 MATLAB 的编组。要从 MATLAB 进行编组,请使用 set 方法或 @ConstructorProperties 注解。