`
hejiajunsh
  • 浏览: 409873 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

JNI之C++调用Java类 —— java.lang.String

阅读更多

原文出處

JNI之C++调用Java类 —— java.lang.String

    为什么要用C++调用Java类?很难回答,写着文章只是觉得JNI很有意思。于是开始编写一段使用VC++在Windows系统里调用java的String类,在C++里调用String类内的一些方法。

    JNI已经被开发了很多年,而在我2年多的Java编程时间里从来没有接触过。直到最近研究JVM实现原理才注意到JNI。 JNI既Java Native Interface,Native这个词我见过我认为最恰当的翻译就是原生。原生的意思就是来自系统自己的,原汁原味的东西,例如Win32 API。Java类需要在虚拟机上运行,也就不是原生的,同样.NET Framework也不是原生的。JNI也就是Java原生接口。关于JNI的规范,以及为什么要使用它,它能做些什么,都在http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html里记述着。

    JNI是规范,它规定了虚拟机的接口,而把具体的实现留给开发者。

    JVM的实现不是唯一的,目前存在很多种Java虚拟机,Sun Hotspot,IBM JDK,还有HP的,Kaffe等等。最流行的就是Sun的Hotspot,最复杂的就是IBM JDK,这是IBM的一贯作风。本文不讨论JVM的实现,只关注JNI。如果您安装了Sun的JDK,您就能在[JAVA_HOME]\include目录下找到jni.h。这个头文件就是虚拟机的唯一接口,你可以调用它声明的函数创建一个JVM。

    在说明C++调用Java类之前,我想先演示一下如果编写Java Native Method。

1.编写带有Native方法的Java类

package org.colimas.jni.test;

public class JniTest {

    static { System.loadLibrary("JniTestImpl"); }  //JVM调用JniTestImpl.dll

    public JniTest(){
    }

    //原生方法
    public native void print(String str);

    /**
    * @param args
    */
    public static void main(String[] args) {
            JniTest test=new JniTest();
            test.print("hello JVM"); //调用原生方法
    }
}

2.使用javah生成c语言头文件。

javah -jni org.colimas.jni.test.JniTest

目录里多了一个org_colimas_jni_test_JniTest.h文件,打开文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class org_colimas_jni_test_JniTest */


#ifndef _Included_org_colimas_jni_test_JniTest
#define _Included_org_colimas_jni_test_JniTest
#ifdef __cplusplus

extern "C" {

#endif

/*
 * Class:     org_colimas_jni_test_JniTest
 * Method:    print
 * Signature: (Ljava/lang/String;)V
 */

JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}

#endif
#endif


其中的Java_org_colimas_jni_test_JniTest_print就是JniTest类里面的print原生方法的C语言声明。

3.编写C代码实现原生方法print

#include <jni.h>
#include "org_colimas_jni_test_JniTest.h" //javah生成的头文件
#include <stdio.h>

JNIEXPORT void JNICALL Java_org_colimas_jni_test_JniTest_print
  (JNIEnv *env, jobject object,jstring str)
{
       //获得字符串
       const char * txt=(*env)->GetStringUTFChars(env,str,0);
       printf("%s\n",txt); //打印到控制台
       return;
}


参数JNIEnv *env,是JNI里最重要的变量。Java.exe创建JVM,之后JVM生成一个env,该env相当于JVM内的Session,可以完成创建Java对象,调用类方法,获得类的属性等等。

在这里env将方法的参数Str从JNI的jstring类型转换为常数char数组。

4.编译

cl  /Ic:\j2sdk1.4.2_10\include /Ic:\j2sdk1.4.2_10\include\win32 /c  JniTestImpl.c

5.连接为DLL

link /dll JniTestImpl.obj

6.设置PATH

set PATH=C:\MyProject\Colimas\CD\JNI\MyJNI;%PATH%

7.运行

java org.colimas.jni.test.JniTest

返回结果

hello JVM

结束

    以上是实现Java原生方法的开发过程,下面进入正题,使用C++调用Java的java.lang.String类。

1. Object类出创建JVM。

使用Java类之前必须要创建JVM环境。JDK由java.exe来完成。本文有Object类的静态方法BeginJVM来创建,用EndJVM来关闭。

创建JVM之后会在创建2个变量,分别是JNIEnv* env和JavaVM* jvm,JNIEnv上文已经说明,JavaVM,顾名思义,代表Java虚拟机,用它来关闭JVM。

Object类的头文件

#include "jni.h"

class Object
{
public:
    static bool BeginJVM();
    static bool EndJVM();
    Object();
    virtual ~Object();

protected:
    static JNIEnv* env;
    static JavaVM* jvm;
};

object.cpp代码

#include "stdafx.h"
#include "JavaClasses.h"
#include "Object.h"

Object::Object()
{}

Object::~Object()
{}

JNIEnv* Object::env=NULL;
JavaVM* Object::jvm=NULL;

//创建JVM

bool Object::BeginJVM()
{

    JavaVMOption options[3];
    JavaVMInitArgs vm_args;

    //各种参数
    options[0].optionString="-Xmx128m";
    options[1].optionString="-Verbose:gc";
    options[2].optionString="-Djava.class.path=.";

    vm_args.version=JNI_VERSION_1_2;
    vm_args.options=options;
    vm_args.nOptions=3;

    //创建JVM,获得jvm和env
    int res = JNI_CreateJavaVM(&jvm,(void **)&env, &vm_args);
    return true;
}

bool Object::EndJVM()
{
    //关闭JVM
    jvm->DestroyJavaVM();
    return true;
}

2. C++的String类调用java.lang.String类方法

编写C++版的String类,调用java String类方法。调用的方法如下:

    String  replaceAll(String regex, String replacement);

    boolean endsWith(String str);

    int indexOf(String str);

    int compareTo(String anotherString);

    char charAt(int i);

String的头文件:

class String  :public Object
{
public:
//与要调用的Java方法名一致。
    const char * replaceAll(char *regex,char *replacement);

    bool endsWith(char * str);

    int indexOf(char * str);

    int compareTo(char *anotherString);

    char charAt(int i);

    String(char *str);

    virtual ~String();
};

实现:

#include "stdafx.h"
#include "String.h"
#include "jni.h"

using namespace std;

jclass clazz;    //全局变量,用来传递class
jobject object;  //全局变量,用来传递object
String::String(char *str)
{
    jstring jstr;

    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    //获得java.lang.String类
    clazz=Object::env->FindClass("java/lang/String");

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    //获得String(String str)构造体
    jmethodID mid= Object::env->GetMethodID(clazz,"<init>", "(Ljava/lang/String;)V");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    //将字符串封装为jstring。
    jstr = Object::env->NewStringUTF(str);

    if (jstr == 0) {
        cerr << "Out of memory" <<endl;
        exit(-1);
    }

    cout << "invoking method" << endl;

    //创建一个java.lang.String对象。
    object=Object::env->NewObject(clazz,mid,jstr);
}

String::~String()
{}

char String::charAt(int i)
{
    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    if (object ==0 ){
        cout << "String object is not created" << endl;
        exit(-1);
    }

    jmethodID mid;

    //获得charAt方法,(I)C表示 参数为int型,返回char型。详细参见JNI规范
    mid = Object::env->GetMethodID(clazz,"charAt", "(I)C");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    jint ji=i;

    cout << "invoking method" << endl;

    //调用charAt
    jchar z = Object::env->CallCharMethod(object,mid,i);

    //返回结果。
    return z;
}


int String::compareTo(char *anotherString)
{

    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    if (object ==0 ){
        cout << "String object is not created" << endl;
        exit(-1);
    }

    jmethodID mid;

    //(Ljava/lang/String;)I表示参数为java.lang.String,返回int
    mid= Object::env->GetMethodID(clazz,"compareTo", "(Ljava/lang/String;)I");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    jstring jstr = Object::env->NewStringUTF(anotherString);
    cout << "invoking method" << endl;

    //调用方法
    jint z=Object::env->CallIntMethod(object,mid,jstr);

    //返回结果
    return z;
}


int String::indexOf(char *str)
{
    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    if (object ==0 ){
        cout << "String object is not created" << endl;
        exit(-1);
    }

    jmethodID mid;
    mid= Object::env->GetMethodID(clazz,"indexOf", "(Ljava/lang/String;)I");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    jstring jstr = Object::env->NewStringUTF(str);
    cout << "invoking method" << endl;

    jint z=Object::env->CallIntMethod(object,mid,jstr);
    return z;
}


bool String::endsWith(char *str)
{

    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    if (object ==0 ){
        cout << "String object is not created" << endl;
        exit(-1);
    }

    jmethodID mid;
    mid= Object::env->GetMethodID(clazz,"endsWith", "(Ljava/lang/String;)Z");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    jstring jstr = Object::env->NewStringUTF(str);
    cout << "invoking method" << endl;

    bool z = Object::env->CallBooleanMethod(object,mid,jstr);
    return z;
}


const char * String::replaceAll(char *regex, char *replacement)
{
    if (Object::env ==NULL){
        cout << "JVM is not created" << endl;
        exit(-1);
    }

    if (clazz ==0 ){
        cout << "Class is not found" << endl;
        exit(-1);
    }

    if (object ==0 ){
        cout << "String object is not created" << endl;
        exit(-1);
    }

    jmethodID mid;
    mid= Object::env->GetMethodID(clazz,"replaceAll", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    if (mid==0){
        cerr<< "GetMethodID Error for class" << endl;
        exit(-1);
    }

    jvalue array[2];
    jstring jreg = Object::env->NewStringUTF(regex);
    jstring jstr = Object::env->NewStringUTF(replacement);

    array[0].l=jreg;
    array[1].l=jstr;

    cout << "invoking method" << endl;

    //传入参数,调用replaceAll方法
    jobject z=Object::env->CallObjectMethodA(object,mid,array);
    const char *result=Object::env->GetStringUTFChars((jstring)z, 0);

    return (const char *)result;
}

3.测试

编写测试代码

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)){
        cerr << _T("Fatal Error: MFC initialization failed") << endl;
        nRetCode = 1;
    } else{
        //创建JVM
        Object::BeginJVM();

        String test("hello");

        //调用replaceAll
        const char *result = test.replaceAll("l","z");

        //返回结果
        cout<< result <<endl;

        //关闭JVM
        Object::EndJVM();
    }
    return nRetCode;
}


4.运行

编译需要 jni.h和jvm.lib文件。

jni.h在[JAVA_HOME]\include

jvm.lib在[JAVA_HOME]\lib

运行需要jvm.dll

jvm.dll在[JAVA_HOME]\ jre\bin\client

运行结果如下:

invoking method

invoking method

hezzo

Press any key to continue

尽管本文的代码很有意思,但我还没有想到有什么价值,以及应用到实际项目中的理由。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/onlymilan/archive/2006/07/20/947652.aspx

分享到:
评论

相关推荐

    3.jni_c++调用java中的方法

    **C++调用Java方法** 1. **加载Java类:** 使用`JNIEnv`指针的`FindClass`方法,传入要查找的Java类的全名(包括包名)。 2. **获取方法ID:** 使用`GetMethodID`,需要提供类的ID、方法的签名以及方法名。方法...

    visual studio 2019下C++通过JNI调用JAVA代码

    在本文中,我们将深入探讨如何在Visual Studio 2019环境下使用C++通过Java Native Interface (JNI)来调用Java代码。JNI是Java平台的一部分,它为Java应用程序提供了与本地代码交互的能力,使得开发者可以将Java应用...

    C++调用java代码的JNI实现

    ### C++调用Java代码的JNI实现概述 在软件开发领域,经常会出现不同语言之间相互调用的需求。本文将深入探讨如何使用C++通过JNI(Java Native Interface)调用来实现对Java代码的调用,特别关注于用户身份验证与...

    Android JNI native调用 java层demo TESTJNI.zip

    本文将深入探讨在Android中如何使用JNI,特别是如何从C++ native代码调用Java层的类、方法、属性以及接口,同时涉及线程回调接口的实现。 首先,我们需要了解JNI的基本结构。一个典型的JNI应用会包含Java源文件、C/...

    JNI技术手册 c/c++调用java

    #### 八、C/C++调用JAVA类 - **加载虚拟机:** - 初始化Java虚拟机。 - **获取指定对象的类定义:** - 使用`FindClass`方法。 - **获取要调用的方法:** - 使用`GetMethodID`方法。 - **调用JAVA类方法:** - ...

    Android中C/C++调用Java代码

    "Android中C/C++调用Java代码" ...Android中C/C++调用Java代码的过程可以分为四步:找到Java类的句柄,实例化Java类,获取Java类的成员函数的句柄,调用Java类的成员函数。这些步骤可以通过JNI提供的函数来实现。

    C++ 调用Java类,已实践

    其中,C++调用Java类的主要途径是通过Java Native Interface (JNI)来实现。 #### JNI简介 JNI(Java Native Interface)是一种标准,用于定义Java应用程序如何与用其他语言编写的本地代码进行交互。它的设计目标是...

    java调用JNI

    将生成的DLL库拷贝至Java项目根目录下,修改`JniDemo.java`文件: ```java package www.java.jira; public class JinDemo { static { System.loadLibrary("JniDemo"); } public native static void set(int i)...

    jni java调用c/c++

    Java 通过 JNI 调用 C/C++ 实现动态库加载 Java Native Interface (JNI) 是 Java虚拟机(JVM)提供的一种接口,允许 Java 代码和本地代码(如 C/C++)之间的交互。通过 JNI,Java 程序可以调用 C/C++ 代码,实现 ...

    qt调用JAVA文件示例

    2. **创建Java类和方法**:在Android Studio或者Eclipse中,编写一个Java类,该类将包含你要在C++中调用的方法。例如,你可以创建一个名为`MyJavaClass`的类,并在其中定义一个静态方法`doSomething()`。 ```java ...

    DELPHI 7 调用 JAVA 接口

    这种通信通常依赖于Java的本地接口(JNI,Java Native Interface),它允许Java代码调用C/C++代码,而Delphi代码可以编译为C++兼容的库。因此,Delphi通过JNI桥接,可以调用Java的静态或实例方法。 1. **配置环境**...

    Android 调用C++代码和C++代码调用源码.zip

    6. **C++调用Java**:在C++代码中,我们也可以通过JNI接口反向调用Java方法。例如,我们可以获取Java对象,调用其成员方法: ```cpp jclass myActivityClass = env-&gt;FindClass("com/example/myapp/MyActivity"); ...

    Android应用源码之代码调用C++代码和C++代码调用代码.zip

    6. **C++调用Java**: 要让C++代码调用Java方法,需要获取到Java对象的引用,然后通过JNIEnv指针调用相应的Java方法。例如,调用一个Java对象的`logMessage`方法: ```cpp jmethodID mid = env-&gt;GetMethodID(cls,...

    java通过jni和c++代码之间实现互相调用

    本教程将深入探讨如何使用 JNI 实现 Java 和 C++ 之间的互相调用,以及如何处理不同类型的数据。 首先,我们需要理解 JNI 的基本概念。JNI 是一个接口,它定义了一套函数,这些函数在 JVM(Java 虚拟机)内部提供对...

    Android APP 用interface 接口的形式对jni进行回调,实例测试

    在Android中,Java接口可以作为参数传递给JNI方法,这样就可以在C/C++代码中调用Java对象的方法。这种方式使得JNI层能够主动通知Java层某些事件的发生,增强了两者之间的通信能力。 1. 创建Java接口 创建一个Java...

    Android JNI c/c++调用java的实例

    "Android JNI C/C++ 调用 Java 的实例" Android JNI (Java Native Interface) 是一种允许 Java 代码和 native 代码之间进行交互的机制。通过 JNI,可以在 Android 应用程序中使用 C/C++ 编写的 native 代码,以提高...

    Android下c++调用java实现内置外置sd卡MP3扫描

    本话题主要探讨如何在Android环境下,使用C++调用Java方法来扫描内置和外置SD卡上的MP3文件,并将扫描结果保存到文件中。 首先,我们需要了解Android的JNI(Java Native Interface)机制,这是Java与本地代码(如...

    Java JNI调用动态库(Linux、Windows)的实现步骤

    ### Java JNI调用动态库(Linux、Windows)的实现步骤 #### 一、概述 Java Native Interface (JNI) 是一种标准的 Java 接口,它允许 Java 代码和其他语言(如 C 或 C++)编写的代码进行交互。通过 JNI,Java 应用...

    java与c++交互(JNI学习笔记)

    ### Java与C++交互(JNI学习笔记) #### 一、Java类型与C/C++类型对应关系 在Java Native Interface (JNI) 中,Java 和 C/C++ 的数据类型有着明确的对应关系。理解这些对应关系是实现Java与C++交互的基础。 - **...

    C++与Java混合编程

    - **C++调用Java**:C++代码需要通过JNI启动Java虚拟机(JVM),并通过JNI调用Java方法。 #### 环境配置 本教程基于以下环境: - Java版本:1.6.0_03-b05 - C++版本:VC++6.0 确保正确设置了环境变量,包括Java的...

Global site tag (gtag.js) - Google Analytics