Android JNI 普通方法和静态方法详解

Android JNI 普通方法和静态方法详解

一、前言

Android Jni中Java的静态方法和普通方法有什么区别?

很多人可能都不清楚,如果想知道的可以了解一下。

比如下面一段代码:

//1、native 的静态方法和普通方法
    public native void normalNativeMethod(); // 声明普通native方法
    public static native void staticNativeMethod(); // 声明静态native方法


//2、Java 的普通方法和静态方法,C++调用过来的处理区别?
    // 普通方法
    public void normalMethod() {
        System.out.println("这是一个普通方法");
    }
    // 静态方法
    public static void staticMethod() {
        System.out.println("这是一个静态方法");
    }

JNI的静态方法包含native的静态方法,以及C++调用Java 的静态方法。
上面两种不同的静态方法,对于JNI来说有啥区别?

这个问题很少人会关注,一个是因为很少会静态方法调用JNI或者回调静态的Java方法;

另外一个是因为知道了或者调试过就不难了,所以很多人觉得没必要讲解和记录。

但是对于JNI 的初学者来说静态方法还是比较陌生的,很容易会懵逼的,不知道有啥区别。

本文主要讲解一下上面两种静态方法在JNI中的区别,有兴趣的可以看看。

二、Android JNI 普通方法和静态方法

1、native 的静态方法和普通方法

这个其实是很简单的,就是类里面的方法和对象的对象里面的方法的区别,这个和Java是完全一样的。

调用nativie的静态方法,只要类名就行,比如:MyClass.staticMethod();

调用nativie 的普通方法就要对象了,如果是本类就是隐藏的this,比如:myClass.method()。

并且Java中定义的nativie静态方法和普通写法,在cpp里面的写法都是一样的。

示例代码如下:

(1) JNI定义nativie普通方法和静态方法
public class MyJNIClass {
    // 声明普通native方法
    public native void normalNativeMethod();
    
    // 声明静态native方法
    public static native void staticNativeMethod();
    
    static {
        System.loadLibrary("myjni"); // 加载C++库
    }
}

这里可以看到jni的库加载的代码就是在static里面的,

所以不管是静态方法还是普通方法都是不必担心库加载的问题。

(2)jni native-lib.cpp中的代码:
#include <jni.h>

extern "C"  JNIEXPORT void JNICALL Java_com_example_myapp_MyJNIClass_normalNativeMethod(JNIEnv* env, jobject obj) {
        // 在这里编写普通native方法的代码
}
    
extern "C"JNIEXPORT void JNICALL Java_com_example_myapp_MyJNIClass_staticNativeMethod(JNIEnv* env, jclass cls) {
        // 在这里编写静态native方法的代码
}

对于cpp代码来说是一点区别都没有的,命名规则那些都是一样的。

(3)调用JNI方法的代码

在Android项目中的MainActivity中,调用这些JNI方法:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        MyJNIClass myJNI = new MyJNIClass();
        
        // 调用普通native方法
        myJNI.normalNativeMethod();
        
        // 调用静态native方法
        MyJNIClass.staticNativeMethod();
    }
}

最大的区别就是调用的时候了,类和类的对象的区别。

所以native普通方法和静态方法,和Java的普通方法和静态方法是一样的,

就是调用的时候需要到的类和类的对象的区别,

静态方法需要类就可以调用,普通方法要类的对象才可以调用。

非要说点其他区别完整的,就把Java那套搬过去就行:

Java中的普通方法和静态方法有以下区别:
1、调用方式不同:
普通方法通过对象实例调用,而静态方法通过类名直接调用。

2、内存分配不同:
普通方法在每个对象实例中都有一份独立的内存空间,
而静态方法在类加载时就已经分配了内存空间,所有对象共享该方法。

3、访问权限不同:
普通方法可以访问类的所有成员(包括静态成员和非静态成员),而静态方法只能访问类的静态成员。

4、静态方法不能访问非静态成员:
由于静态方法在对象创建之前就已经存在,所以无法访问需要通过对象实例才能访问的非静态成员。

5、静态方法可以直接调用:
由于静态方法不依赖于对象实例,所以可以在没有创建对象的情况下直接调用。

6、静态方法不能被重写:
由于静态方法是通过类名直接调用的,所以无法被子类重写。

2、cpp调用Java普通方法和静态方法区别

先看一下下面的示例代码:

(1) Java定义普通方法和静态方法
public class MyJNIClass {
    // 普通方法
    public void normalMethod() {
        System.out.println("这是一个普通方法");
    }
    
    // 静态方法
    public static void staticMethod() {
        System.out.println("这是一个静态方法");
    }
}

这里就是一个最普通的Java类,定义了一个普通方法和静态方法。

后面cpp代码会调用Java代码,执行程序后就可以看到打印。

(2)jni native-lib.cpp中的代码:
#include <jni.h>

extern "C"  JNIEXPORT void JNICALL Java_com_example_myapp_MainActivity_callNormalMethod(JNIEnv* env, jobject obj) {
        // 获取MyJNIClass类
        jclass cls = env->FindClass("com/example/myapp/MyJNIClass");
        
        // 获取普通方法的方法ID
        jmethodID methodId = env->GetMethodID(cls, "normalMethod", "()V");
        
        // 创建MyJNIClass对象
        jobject jniObj = env->AllocObject(cls);
        
        // 调用普通方法
        env->CallVoidMethod(jniObj, methodId);
    }
    
extern "C" JNIEXPORT void JNICALL Java_com_example_myapp_MainActivity_callStaticMethod(JNIEnv* env, jobject obj) {
        // 获取MyJNIClass类
        jclass cls = env->FindClass("com/example/myapp/MyJNIClass");
        
        // 获取静态方法的方法ID
        jmethodID methodId = env->GetStaticMethodID(cls, "staticMethod", "()V");
        
        // 调用静态方法
        env->CallStaticVoidMethod(cls, methodId);
    }

其实关键就在这里,静态方法和普通方法调用的api函数是不一样的;

具体区别:

1、获取方法签名的api函数不同
GetMethodID 是获取普通方法签名id的方法;GetStaticMethodID是获取静态方法签名id的方法;

2、需要的调用对象不同
静态方法使用类就可以调用,普通方法还有获取到类的对象

3、反射执行调用普通方法和静态方法的api函数不同
CallVoidMethod 是普通方法执行的api函数,CallStaticVoidMethod 是静态方法执行的api函数;
这里只是一个举例,如果不是void的方法,那么api函数是不同的,
比如调用一个返回Int的方法,反射调用的api函数就是 CallIntMethod,其他的方法以此类推
(3)调用JNI方法的代码

在Android项目中的MainActivity中,调用这些JNI方法:

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("myjni"); // 加载C++库
    }
    
    public native void callNormalMethod();
    public native void callStaticMethod();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 调用普通方法
        callNormalMethod();
        
        // 调用静态方法
        callStaticMethod();
    }
}

执行程序后,就可以看到 MyJNIClass 类里面的静态方法和普通方法的打印日志。

三、其他

1、Android JNI 普通方法和静态方法小结

Java中定义的普通native方法和静态nativie方法区别:

两种方法没啥太大区别,cpp代码的写法是一样的,

区别就是Java的普通方法和静态方法的区别,使用的时候需要的调用对象不同,

普通方法是类的对象进行调用,静态方法是类直接进行调用。

cpp调用Java普通方法和静态方法区别:


cpp代码里面的实现api函数不同,调用静态方法获取类,调用普通方法要获取类的对象,

静态方法的调用一般是api函数里面多了Static关键字。

本文的内容精华,就是上面几句。

理解一下,或者操作试试,就会更加印象深刻。

2、Android Jni的介绍和简单Demo实现

之前写的文章,包含了简单使用到的api函数

https://blog.csdn.net/wenzhi20102321/article/details/136291126

3、 Android JNI复杂用法,回调,C++中调用Java方法

JNI C++调用Java代码实现和相关知识 :

https://blog.csdn.net/wenzhi20102321/article/details/136419405

共勉: 今天很残酷,明天更残酷,后天很美好 …

相关推荐

  1. Android JNI 普通方法静态方法详解

    2024-03-10 23:28:03       25 阅读
  2. synchronized用于静态方法普通方法有区别吗?

    2024-03-10 23:28:03       13 阅读
  3. 构造方法普通方法区别是啥?

    2024-03-10 23:28:03       16 阅读
  4. Kotlin标准函数静态方法

    2024-03-10 23:28:03       12 阅读
  5. 【逆向】fridaAPI_如何hook一个静态方法实例方法

    2024-03-10 23:28:03       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-10 23:28:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-10 23:28:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-10 23:28:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-10 23:28:03       20 阅读

热门阅读

  1. .Net预处理器指令

    2024-03-10 23:28:03       23 阅读
  2. CSS、less、Sass、Scss、Stylus的认识

    2024-03-10 23:28:03       20 阅读
  3. Vue3中如何将一个div进行拖拽

    2024-03-10 23:28:03       22 阅读
  4. SpringBoot整合ActiveMQ步骤

    2024-03-10 23:28:03       19 阅读
  5. Kafka|处理 Kafka 消息丢失的有效措施

    2024-03-10 23:28:03       21 阅读
  6. Rust 语言的 println! 宏的格式占位符

    2024-03-10 23:28:03       19 阅读
  7. 代码随想录 贪心算法-简单题目

    2024-03-10 23:28:03       17 阅读
  8. Open vSwitch: 深入解析现代网络虚拟化的核心

    2024-03-10 23:28:03       22 阅读
  9. python的tqdm库不显示动态进度条的问题

    2024-03-10 23:28:03       23 阅读