王学岗NDK系列(二):JNI:c /c++调用java属性和函数

**1,c/c++ 调用java中的实例属性

**
看下MainActivity的代码

package com.example.acer.test_18_02_21;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    int anInt=10;
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        Log.i("zhang_xin",anInt+"值值值值值");
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

native-lib

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
        //通过对象实例来获取jclass,相当于java中的getClass方法
    jclass cls = env->GetObjectClass(jobj);
    //获取类中某个非静态成员变量的ID(域ID)
    //anInt:MainActivity中的属性名称
    //I:属性签名,int值的签名是一个大写的I
    jfieldID jintid = env->GetFieldID(cls, "anInt", "I");
    //第一个参数:某个 Java 对象实例
    //field就是英文属性、成员变量
    //此时a的值就是MainActivity中定义的anInt的值,即10;
    jint a=env->GetIntField(jobj, jintid);
    a=25;
    //修改MainActivity中anInt的值
    env->SetIntField(jobj,jintid,a);

    std::string hello = "Hello 我乃西凉马超是也from C++";
    return env->NewStringUTF(hello.c_str());
}

MainActivity显示修改后的anInt值是25
总结下步骤:

1)先获取当前类
2)再获取属性ID
3)env环境指针调用相关方法,需要参数,get和set函数(方法)
**

2,c/c++调用java中的静态属性

**
MainActivity代码

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    static int s_anInt=11;
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("zhang_xin",s_anInt+"前");
        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        Log.i("zhang_xin",s_anInt+"后");
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

native-lib代码

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    //静态用到cls替代
    jclass  cls=env->GetObjectClass(jobj);
    jfieldID js_intid=env->GetStaticFieldID(cls,"s_anInt","I");
    //得到MainActivity中s_anInt的值,为11
    jint a= env->GetStaticIntField(cls,js_intid);
    env->SetStaticIntField(cls, js_intid,60);
    std::string hello = "Hello 我乃西凉马超是也from C++";
    return env->NewStringUTF(hello.c_str());
}

看下打印输出结果

02-22 18:38:07.358 25368-25368/? I/zhang_xin: 11前
02-22 18:38:07.358 25368-25368/? I/zhang_xin: 60后

总结下步骤:

  1. 先获取当前类
    2)在获取属性ID
    3)env调用相关方法,和普通的变量区别是参数不同
    **

3.c/c++调用java类的实例方法

**
看下MainActivity类的代码

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

     
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        
        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        

    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public int temp(int a){
        Log.i("zhang_xin",a+"C++中调用");
        return a;
    }
}

native-lib中的代码

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {

    jclass cls = env->GetObjectClass(jobj);
    //cls:来自哪个class
    //方法的名称
    //方法的签名:括号里面的I是参数类型,后面的I是返回值类型
    jmethodID jmid=env->GetMethodID(cls,"temp","(I)I");
    //第一个参数,Java对象实例
    //第二个参数,methodID:指定方法的ID
   //第三个参数	args:输入参数列表
     //调用方法使用Call**;
    //jobj 此处代表MainActivityl.class;
    //三个点代表可变参数,MainActivity方法中的参数
    env->CallIntMethod(jobj, jmid,56);
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}

看下MainActivity的输出

56C++中调用

在这里有一点要注意,CallIntMethod在执行中会转化为CallIntMethodv,当参数不明确的时候需要调用CallIntMethodA;

步骤
1)先获取当前类
2)再获取属性ID
3)env call系列
jclass cls = env->GetObjectClass(jobj);
jmethodID jmid = env->GetMethodID(cls,“temp”,"(I)I");
env->CallIntMethod(jobj, jmid,56);
**

4,C/C++调用java静态方法

**
看下MainActivity

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());


    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public static int stemp(int a,String str){
        Log.i("zhang_xin",a+"  C++中调用  "+str);
        return a;
    }
}

native-lib

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {

    jclass cls = env->GetObjectClass(jobj);
    //String类型是一个类类型,大写的L+类的全名,所以是Ljava/lang/String;
    jmethodID jsmid = env->GetStaticMethodID(cls,"stemp","(ILjava/lang/String;)I");
    jstring str=env->NewStringUTF("zhang_xin");
    env->CallStaticIntMethod(cls, jsmid,41,str);
    std::string hello = "Hello 我乃关羽是也from C++";
    return env->NewStringUTF(hello.c_str());
}

看下打印输出的结果

I/zhang_xin: 41  C++中调用  zhang_xin

**

5,c/c++调用其他子类的方法

**
我们创建一个父类和一个子类

package com.example.acer.test_18_02_21;

/**
 * Created by acer on 2018/2/22.
 */

public class Father {
    public Father(){

    }
    public void drive(){
        System.out.println("我会开车");
    }

}

package com.example.acer.test_18_02_21;

/**
 * Created by acer on 2018/2/22.
 */

public class Son extends Father {

    public Son(){
    }

    @Override
    public void drive() {
        System.out.println("我正在学开车");

    }
}

看下MainActivity类

package com.example.acer.test_18_02_21;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    Father son1=new Son();

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());



    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

}

看下native-lib

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {
    jclass cls = env->GetObjectClass(jobj);
    jfieldID jsid=env->GetFieldID(cls,"son1","Lcom/example/acer/test_18_02_21/Father;");
     //Son类是一个Object
    jobject son1=env->GetObjectField(jobj, jsid);
    //通过当前对象找到该类
    jclass  cls_son=env->GetObjectClass(son1);
    //注意这里的class是Son类的Class;方法名drive
    jmethodID jomid = env->GetMethodID(cls_son, "drive", "()V");
    //注意jobj是MainActivity的,这里不能用,我们要用son1
    //没有参数传空
    env->CallVoidMethod(son1, jomid, NULL);
    std::string hello = "Hello 我乃关羽是也from C++";
    return env->NewStringUTF(hello.c_str());
}

看下输出结果

System.out: 我正在学开车

步骤:先获取子类对象,然后访问子类的方法
**

6,c/c++通过子类对象调用父类方法

**
其他的三个类与5一样;我们只需改下native-lib的方法

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

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_acer_test_118_102_121_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jobj) {


    jclass cls = env->GetObjectClass(jobj);
    jfieldID jsid=env->GetFieldID(cls,"son1","Lcom/example/acer/test_18_02_21/Father;");
    jobject son1=env->GetObjectField(jobj, jsid);
    jclass  cls_son=env->GetObjectClass(son1);
    //父类的class
    jclass jfcls = env->GetSuperclass(cls_son);
    //方法的ID
    jmethodID jfomid = env->GetMethodID(jfcls,"drive","()V");
    //这里要传两个对象,一个是子类对象,一个是父类对象
    env->CallNonvirtualVoidMethod(son1, jfcls, jfomid, NULL);
    std::string hello = "Hello 我乃张飞是也from C++";
    return env->NewStringUTF(hello.c_str());
}

看下运行结果

我会开车

7,获取某个类方法签名的窍门
首先找到该类,以Father类为例;
这里写图片描述
其次,在Terminal中,进入该类的目录
这里写图片描述
最后输入 javap -s -p Father
获取类的方法签名
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值