JNA——模拟c++中类及成员

JNA——模拟c++中类及成员

前言:

        最近正在学习JNA相关知识,但在寻找教程的过程中,发现基本上教程都是针对单个方法的,最多最多介绍至结构体及相关方法的使用。

        众所周知,Java是一门面向对象的语言,而C++中也添加了对于类的支持,所以如何通过JNA去调用C++中的类及方法呢?那么接下来就进行介绍.....

目录

JNA——模拟c++中类及成员

前言:

C++内容:

  1. Person类(C++)

     (1) h文件(Person.h)

     (2)cpp文件(Person.cpp)

  2. 外部调用接口

     (1)h文件(JNAPerson.h)

     (2)cpp文件(JNAPerson.cpp)

  3. 预编译标头文件(pch.h)

Java内容:

  1. JNA相关接口(dllTest.java)

  2. Person类(Java)

  3. 测试


C++内容:

        我们的最终目标为:构建一个C++中的Person类,在Java中也可以对其进行调用。

        首先进行C++中类的构建。

  1. Person类(C++)

     (1) h文件(Person.h)

        先对Person类进行声明,此处沿用面向对象思路,将具体属性隐藏,暴露get与set方法。

#pragma once
class Person
{
private:
	wchar_t* name;
	int age;
public:
	wchar_t* getName();
	int getAge();
	void setName(wchar_t*);
	void setAge(int);
	void print();
};

     (2)cpp文件(Person.cpp)

        具体实现。

#include "pch.h"
#include "Person.h"
#include <iostream>

using namespace std;

wchar_t* Person::getName(){
    return name;
}

int Person::getAge(){
    return age;
}

void Person::setName(wchar_t* name){
    this->name = name;
}

void Person::setAge(int age){
    this->age = age;
}

void Person::print(){
    cout << "age:" << age << ", name:" << name << endl;
}

  2. 外部调用接口

     (1)h文件(JNAPerson.h)

       先将已经声明及实现的Person类包含进来,再开始声明用于Java中JNA调用的外部接口函数。

        可能有同学已经注意到了,除了Person类中已经有的get、set方法以外,还有一个Person_ctor方法,这个方法对应的是Person类的构造函数,返回一个Person对象的指针,且其余方法都会通过这个指针来进行调用。

        这么说可能会有点难懂,建议直接看接下来的cpp文件就可以理解了。

#pragma once
#include "Person.h"
#define MYLIBAPI extern "C" _declspec(dllexport)  //指的是允许将其给外部调用

MYLIBAPI Person* Person_ctor();

MYLIBAPI wchar_t* getName(Person* person);
MYLIBAPI int getAge(Person* person);
MYLIBAPI void setName(Person* person, wchar_t* name);
MYLIBAPI void setAge(Person* person, int age);
MYLIBAPI void print(Person* person);

     (2)cpp文件(JNAPerson.cpp)

        可以看到,这些函数都是围绕Person对象的指针进行的,这是因为对于Java而言,我们无需关心C++中类的具体实现,也就无需对Java中的类添加具体的成员变量,我们仅需通过这种方式将Java中的类封装成 “好像它看起来就是一个真的类” 就行了。

#include "pch.h"
#include "JNAPerson.h"

Person* Person_ctor(){
	return new Person();
}

wchar_t* getName(Person* person){
	return person->getName();
}

int getAge(Person* person){
	return person->getAge();
}

void setName(Person* person, wchar_t* name){
	person->setName(name);
}

void setAge(Person* person, int age){
	person->setAge(age);
}

void print(Person* person){
	person->print();
}

  3. 预编译标头文件(pch.h)

        C++中,最后将JNAPerson.h的头文件添加至预编译即可,在通过编译后,得到了dll文件

// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"
#include "JNAPerson.h"

#endif //PCH_H

Java内容:

        在C++获得dll文件之后,将其放置于工程根目录下

  1. JNA相关接口(dllTest.java)

        该接口继承的是com.sun.jna中的Library接口。

        首先进行dll的加载,需要注意的是 loadLibrary 方法中含有两个参数,第一个参数就是动态链接库不含后缀名的名称,在Windows下就是dll文件的名称。此处通过C++获取的dll文件名为 "DllTest" ,也可自行进行修改,第二个参数则是当前接口.class。

        其次进行接口函数的定义,JNA会自动帮你将这些函数去与dll中的函数一一对应起来,但需要注意的是通过JNA转换前后的类型并不一致,可自行进行搜索。

        另外,此处接口定义的函数与C++中向JNA暴露的函数可以存在不一致的情况,多一些或者少一些都不影响。

package com.study.test.jna;

import com.sun.jna.*;

public interface DllTest extends Library {
    DllTest INSTANCE = (DllTest) Native.loadLibrary(Platform.isWindows() ? 
"DllTest" : "", DllTest.class);

    Pointer Person_ctor();
    WString getName(Pointer pointer);
    int getAge(Pointer pointer);
    void setName(Pointer pointer, WString name);
    void setAge(Pointer pointer, int age);
    void print(Pointer pointer);
}

  2. Person类(Java)

        其实对于Java中类的对象,最根本的还是需要与C++中的对象一 一对应,所以此处在构造函数中,将C++的对象指针保存至self中,后续全部的功能调用也是通过该指针,而暴露在外的功能也可正常编写进行调用了~

        另外需要注意的是,此处全部方法的实现都是需要通过JNA接口中的INSTANCE实例进行调用的。

package com.study.test.jna;

import com.sun.jna.Pointer;
import com.sun.jna.WString;

public class Person {
    private final Pointer self; // 对应C++中的Person对象指针

    Person(){
        self = DllTest.INSTANCE.Person_ctor();
    }

    String getName(){
        return DllTest.INSTANCE.getName(self).toString();
    }

    int getAge(){
        return DllTest.INSTANCE.getAge(self);
    }

    void setName(String name){
        DllTest.INSTANCE.setName(self, new WString(name));
    }

    void setAge(int age){
        DllTest.INSTANCE.setAge(self, age);
    }

    void print(){
        DllTest.INSTANCE.print(self);
    }
}

  3. 测试

package com.study.test.jna;


public class TestDemo {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(22);
        person.setName("B");
        System.out.println("This is age:"+person.getAge());
        System.out.println("This is name:"+person.getName());
        person.print();
    }
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值