JNI 调用 Java 父类方法以及字符乱码问题

本文详细介绍了如何在Java和C++通过JNI进行交互,包括创建子类实例、调用父类方法,并解决中文字符串乱码问题。重点展示了JNI的实践应用和跨语言数据传递技巧。

1 Java 代码

父类代码:

package com.karashok;

public class Human {

    public void sayHi() {
        System.out.println("Human say Hi!");
    }
}

子类代码:

package com.karashok;

public class Man extends Human{

    @Override
    public void sayHi() {
        System.out.println("Man say Hi!");
    }
}

JNI 代码:

package com.karashok;

import java.util.Date;

public class JNIDemo {

    public Human human = new Man();

    /**
     * 调用构造方法
     * @return
     */
    public native Date accessConstructor();

    /**
     * 调用父类方法
     */
    public native void accessSuperMethod();

    /**
     * 中文字符问题
     * @param str
     * @return
     */
    public native String chineseString(String str);
}

main 代码:

package com.karashok;

public class Main {

    static {
        System.load("libDemo.dylib");
    }
    public static void main(String[] args) {
        JNIDemo demo = new JNIDemo();
        System.out.println("----- 获取构造方法 -----");
        System.out.println("方法返回值: " + demo.accessConstructor());

        System.out.println("----- 获取父类方法 -----");
        demo.accessSuperMethod();

        System.out.println("----- 中文字符问题 -----");
        System.out.println("方法返回值: " + demo.chineseString("宋喆"));
    }
}

2 C 代码:

头文件代码:

#include "jni.h"
#include <string.h>

#ifndef DEMO_LIBRARY_H
#define DEMO_LIBRARY_H

/*
 * Class:     com_karashok_JNIDemo1
 * Method:    accessConstructor
 * Signature: ()Ljava/util/Date;
 */
JNIEXPORT jobject JNICALL Java_com_karashok_JNIDemo1_accessConstructor
(JNIEnv *, jobject);

JNIEXPORT void JNICALL Java_com_karashok_JNIDemo1_accessSuperMethod
(JNIEnv *, jobject);

JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo1_chineseString
(JNIEnv *, jobject, jstring);
#endif //DEMO_LIBRARY_H

实现代码:

#include "library.h"

/*
 * Class:     com_karashok_JNIDemo1
 * Method:    accessConstructor
 * Signature: ()Ljava/util/Date;
 */
JNIEXPORT jobject JNICALL Java_com_karashok_JNIDemo1_accessConstructor(JNIEnv *jniEnv, jobject jobj) {
    jclass cls = (*jniEnv)->FindClass(jniEnv,"java/util/Date");
    jmethodID mid = (*jniEnv)->GetMethodID(jniEnv,cls,"<init>","()V");
    jobject dataObj = (*jniEnv)->NewObject(jniEnv,cls,mid);
    jmethodID dataMid = (*jniEnv)->GetMethodID(jniEnv,cls,"getTime","()J");
    jlong time = (*jniEnv)->CallLongMethod(jniEnv,dataObj,dataMid);
    printf("time: %ld\n",time);
    return dataObj;
}

JNIEXPORT void JNICALL Java_com_karashok_JNIDemo1_accessSuperMethod(JNIEnv *jniEnv, jobject jobj) {
    jclass  jcls = (*jniEnv)->GetObjectClass(jniEnv,jobj);
    jfieldID manFid = (*jniEnv)->GetFieldID(jniEnv,jcls,"human","Lcom/karashok/Human;");
    jobject manObj = (*jniEnv)->GetObjectField(jniEnv,jobj,manFid);

    // 正常获取方法
    jclass manCls = (*jniEnv)->GetObjectClass(jniEnv,manObj);
    jmethodID manMid = (*jniEnv)->GetMethodID(jniEnv,manCls,"sayHi","()V");
    (*jniEnv)->CallObjectMethod(jniEnv,manObj,manMid);


    // 获取父类方法
    jclass humanCls = (*jniEnv)->FindClass(jniEnv,"com/karashok/Human");
    jmethodID humanMid = (*jniEnv)->GetMethodID(jniEnv,humanCls,"sayHi","()V");
    (*jniEnv)->CallNonvirtualObjectMethod(jniEnv,manObj,humanCls,humanMid);
}

JNIEXPORT jstring JNICALL Java_com_karashok_JNIDemo1_chineseString(JNIEnv *jniEnv, jobject jobj, jstring jstr) {
    char *cStr = (*jniEnv)->GetStringUTFChars(jniEnv,jstr,JNI_FALSE);
    printf("Input str: %s\n",cStr);

    char *cOutStr = "马蓉与宋喆";
    jstring outStr1 = (*jniEnv)->NewStringUTF(jniEnv,cOutStr);

    // 如果出现乱码是由于不同电脑的编码格式不同,这个需要指定编码格式
    jclass strCls = (*jniEnv)->FindClass(jniEnv,"java/lang/String");
    jmethodID constructor_mid = (*jniEnv)->GetMethodID(jniEnv,strCls,"<init>","([BLjava/lang/String;)V");
//
    jbyteArray jba = (*jniEnv)->NewByteArray(jniEnv, strlen(cOutStr));
    (*jniEnv)->SetByteArrayRegion(jniEnv,jba,0,strlen(cOutStr),cOutStr);
    jstring charsetName = (*jniEnv)->NewStringUTF(jniEnv,"GB2312");
    jstring outStr2 = (*jniEnv)->NewObject(jniEnv,strCls,constructor_mid,jba,charsetName);
    return outStr2;
}

3 总结

  1. 调用父类方法,其实就是获取父类的类然后用子类对象调用,即可映射到父类方法。
  2. 中文乱码问题,调用 String 的方法加入编码格式即可。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值