您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

使用SWIG生成Java接口

使用SWIG生成Java接口

您可以使用“ Directors ”使用SWIG + Java来实现所需的功能,但是它并不是您所希望的那样从C @H_301_1@抽象类到Java的直接映射。因此,我的答案分为三个部分-首先是在Java中实现C 纯虚函数的简单示例,其次解释了为什么输出是这样,第三是“变通方法”。

给定头文件(module.hh):

#include <string>
#include <iosfwd>

class Interface {
public:
  virtual std::string foo() const = 0;
  virtual ~Interface() {}
};

inline void bar(const Interface& intf) {
  std::cout << intf.foo() << std::endl;
}

我们希望将其包装起来并使其从Java方面直观地工作。我们可以通过定义以下SWIG接口来做到这一点:

%module(directors="1") test

%{
#include <iostream>
#include "module.hh"
%}

%feature("director") Interface;
%include "std_string.i"

%include "module.hh"

%pragma(java) jniclasscode=%{
  static {
    try {
        System.loadLibrary("module");
    } catch (UnsatisfiedLinkError e) {
      System.err.println("Native code library Failed to load. \n" + e);
      System.exit(1);
    }
  }
%}

在这里,我们为整个模块启用了Director,然后要求将它们class Interface专门用于。除此之外,还有我最喜欢的“自动加载共享对象”代码,没有什么特别值得注意的。我们可以使用以下java类对此进行测试:

public class Run extends Interface {
  public static void main(String[] argv) {
    test.bar(new Run());       
  }

  public String foo() {
    return "Hello from Java!";
  }
}

然后,我们可以运行它并看到它正在按预期运行:

ajw @ rapunzel:?/ code / scratch / swig / javaintf> java 从Java运行Hello!

如果你用它既不快乐abstract,也不是interface你可以停止阅读这里,导演做你需要的一切。

但是,SWIG已将看起来像抽象类的东西变成了具体的类。这意味着在Java方面,我们可以合法地编写new Interface();,这没有任何意义。为什么SWIG会这样做?该class甚至没有abstract,更不用说interface(见点4在这里),它会觉得在Java端更自然。答案是双重的:

Interface *find_interface();

在这里,SWIG对返回类型的了解仅是type Interface。在理想的世界中,它会知道派生的类型是什么,但是仅从函数签名中就无法解决这个问题。这意味着,在生成的Java某处有将必须要在通话new Interface,如果这是不可能的/法律Interface是在Java端抽象。

如果您希望提供此接口作为接口,以便用Java表示具有多重继承的类型层次结构,那将是相当有限的。但是有一种解决方法

public interface Interface {
    public String foo();
}

修改SWIG接口文件

这将导致模块文件现在看起来像:

%module(directors="1") test

%{
#include <iostream>
#include "module.hh"
%}

%feature("director") Interface;
%include "std_string.i"

// (2.1)
%rename(NativeInterface) Interface; 

// (2.2)
%typemap(jstype) const Interface& "Interface";

// (2.3)
%typemap(javainterfaces) Interface "Interface"

// (2.5)
%typemap(javain,pgcppname="n",
         pre="    NativeInterface n = makeNative($javainput);")
        const Interface&  "NativeInterface.getCPtr(n)"

%include "module.hh"

%pragma(java) modulecode=%{
  // (2.4)
  private static class NativeInterfaceProxy extends NativeInterface {
    private Interface delegate;
    public NativeInterfaceProxy(Interface i) {
      delegate = i;
    }

    public String foo() {
      return delegate.foo();
    }
  }

  // (2.5)
  private static NativeInterface makeNative(Interface i) {
    if (i instanceof NativeInterface) {
      // If it already *is* a NativeInterface don't bother wrapping it again
      return (NativeInterface)i;
    }
    return new NativeInterfaceProxy(i);
  }
%}

现在我们可以包装一个类似的函数

// %inline = wrap and define at the same time
%inline %{
  const Interface& find_interface(const std::string& key) {
    static class TestImpl : public Interface {
      virtual std::string foo() const {
        return "Hello from C++";
      }
    } inst;
    return inst;
  }
%}

并像这样使用它:

import java.util.ArrayList;

public class Run implements Interface {
  public static void main(String[] argv) {
    ArrayList<Interface> things = new ArrayList<Interface>();
    // Implements the interface directly
    things.add(new Run()); 
    // NativeInterface implements interface also
    things.add(test.find_interface("My lookup key")); 

    // Will get wrapped in the proxy 
    test.bar(things.get(0));

    // Won't get wrapped because of the instanceOf test
    test.bar(things.get(1));
  }

  public String foo() {
    return "Hello from Java!";
  }
}

现在可以按照您希望的那样运行:

ajw @ rapunzel:?/ code / scratch / swig / javaintf> java 从Java运行Hello! 您好,C ++

而且,我们完全像Java程序员所期望的那样,将C ++中的抽象类包装为Java中的接口!

java 2022/1/1 18:15:14 有444人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶