Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用

2023-10-30

前言
一直觉得无论是从行业形式来看,还是从就业角度说,学习JNI/NDK开发是一条必经之路。很多说Android和IOS几乎没有市场了,其实只能说现在开发APP的需求没那么多了,再加上之前培训机构疯狂向市场输出Android/IOS开发人员,导致市场供过于求,难免出现一职难求的现象。不过我不认为Android会死,虽然APP的需求少了,但是Android又不是只能做APP,除非你只会APP开发。哈哈

第一部分:环境配置和简单demo运行参考
Android JNI/NDK开发(一)NDK真的很难吗?

1.1JNI/NDK在Android studio 上基本配置

参考连接http://blog.csdn.net/krubo1/article/details/50547681

1.2Android Studio 定制快速生成Jni 头文件工具 NDK教程

参考连接http://blog.csdn.net/silver_R/article/details/48457077

备注1:
在jni文件下添加一个空的C文件 empty.c 能解决如下报错

Error:Execution failed for task ‘:app:compileDebugNdk’. 
NDK_PROJECT_PATH=null

备注2:
在 app > build.gradle 中配置ndk

        //ndk配置
        ndk {
            moduleName "RLibs"
            //so文件包名
            stl "stlport_static"
            //NDK中C++标准库、STL的配置
            //如未配置可能出现错误: fatal error: iostream: No such file or directory
            ldLibs "log", "z", "m"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }

第二部分(使用Android studio实现):JNI实现C++与Java之间函数的相互调用

我们知道Java和C/C++是两种不同的语言,不能直接通信,所以需要通过中间桥梁JNI将他们连接起来。

JNI充当中间桥梁,那么它肯定存在很多函数可以将Java的基本数据类型转化为JNI通用的类型,相对于C/C++也是一样。下面给出一个

JNI中文学习文档http://www.cnblogs.com/jycboy/archive/2016/04/15/5396876.html#jialianbendi

给出一片文档就算了?那怎么可能啊,当时我在网上看到这个文档的时候我觉得JNI没问题了,但还是动手试了一下,不试不知道,动手一敲,一脸懵逼。那还是跟着看看Java层代码是如何跟C/C++代码交互的吧。

需求:
1.1:Java调用C++方法获取基本数据类型(int,double,string)
1.1:Java调用C++无返回值方法
2.1:C++调用Java非静态方法获取基本数据类型(int,double,string)
2.2:C++调用Java静态方法获取返回值
2.3:C++调用Java无返回值方法

OK,Java中写一个native工具类,定义native方法,以及Java中方法的实现

/**
 * native工具类
 *
 * @author ZhongDaFeng
 * @date 2017/5/3 14:48
 */
public class NativeUtils {

    public static Context mContext;

    static {
        System.loadLibrary("RLibs");
    }

    //从native获取int类型数据
    public native int getIntFromNative(int javaInt);

    //从native获取double类型数据
    public native double getDoubleFromNative(double javaDouble);

    //从native获取string类型数据
    public native String getStringFromNative(String javaString);

    //从native获取ArrayList<String>类型数据
    public native ArrayList<String> getArrayListFromNative(ArrayList<String> javaList);

    //模拟native层调用安卓Toast
    public native void nativeCallAndroidToast();

    //模拟native层调用java基本类型信息
    public native String nativeCallJavaBaseMsg();


    //native获取int类型数据
    public int getIntFromJava(int nativeInt) {
        int javaInt = 100;
        return javaInt + nativeInt;
    }

    //native获取double类型数据
    public double getDoubleFromJava(double nativeDouble) {
        double javaDouble = 100.0;
        return javaDouble + nativeDouble;
    }

    //native获取string类型数据
    public String getStringFromJava(String nativeString) {
        String javaStr = " Java Static String : ";
        String split = " call ";
        return nativeString + split + javaStr ;
    }

    //native获取ArrayList<String>类型数据
    public ArrayList<String> getArrayListFromJava(ArrayList<String> nativeList) {
        return null;
    }

    //native 获取静态方法数据
    public static String getStringFromJavaWithStatic(String nativeString) {
        String javaStr = " java static string  ";
        String split = " && ";
        return javaStr + split + nativeString;
    }

    // 提示信息,提供JNI调用
    public void showToast(String msg) {
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }

}

根据这个类生成com_r_ndk_NativeUtils.h头文件(文章开头有说明如何生成)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_r_ndk_NativeUtils */

#ifndef _Included_com_r_ndk_NativeUtils
#define _Included_com_r_ndk_NativeUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getIntFromNative
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_r_ndk_NativeUtils_getIntFromNative
  (JNIEnv *, jobject, jint);

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getDoubleFromNative
 * Signature: (D)D
 */
JNIEXPORT jdouble JNICALL Java_com_r_ndk_NativeUtils_getDoubleFromNative
  (JNIEnv *, jobject, jdouble);

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getStringFromNative
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_r_ndk_NativeUtils_getStringFromNative
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getArrayListFromNative
 * Signature: (Ljava/util/ArrayList;)Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_com_r_ndk_NativeUtils_getArrayListFromNative
  (JNIEnv *, jobject, jobject);

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    nativeCallAndroidToast
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_r_ndk_NativeUtils_nativeCallAndroidToast
  (JNIEnv *, jobject);

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    nativeCallJavaBaseMsg
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_r_ndk_NativeUtils_nativeCallJavaBaseMsg
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

复制h文件,修改为C/C++文件(随便命名)实现业务逻辑

第一个需求:Java调用C++方法获取基本数据类型(int,double,string)

先编写C++逻辑

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getIntFromNative
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_r_ndk_NativeUtils_getIntFromNative
  (JNIEnv * env, jobject obj, jint j_int){
   int result=50;
   result+=j_int;
   return result;
  }

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getDoubleFromNative
 * Signature: (D)D
 */
JNIEXPORT jdouble JNICALL Java_com_r_ndk_NativeUtils_getDoubleFromNative
  (JNIEnv * env, jobject obj, jdouble j_double){
    double result=50.0;
     result+=j_double;
     return result;
  }

这两个函数,不难看出,JNI接受从Java传递过来的int /double类型的值,在本地代码(C++)中加上一定的值然后再返回给Java
jint/jdouble/jstring 等等是JNI的数据类型(第一篇博客中有说明),在C++中int/double类型可以直接转为对应的JNI类型使用。
所以到这里我们解决了一个问题:
从Java传递值过来,在生成h头文件的时候会直接转化为JNI对应的数据类型 int=>jint,而对于C/C++中int/double等类型可以直接转化为JNI的类型使用,那么JNI就将Java和C++这些基本的数据类型连接起来了。

这个不难,相对可恶的是string类型的数据,我们知道其实string不是Java的基本数据类型,而是封装的对象,所以这个string的处理比较麻烦一点。现在来分析一下string字符串处理的函数,代码:

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    getStringFromNative
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_r_ndk_NativeUtils_getStringFromNative
  (JNIEnv * env, jobject obj, jstring j_string){

      const char *java_str_char = env->GetStringUTFChars(j_string, NULL);//获取java字符串
      if(java_str_char == NULL){
        return NULL;
      }
      char const *native_char = " Native :";
      char const *split_char = " call ";
      std::string const& temp = std::string(java_str_char) +std::string(split_char) + std::string(native_char);
      char const *result = temp.c_str();
      env->ReleaseStringUTFChars( j_string, java_str_char);//释放
      return env->NewStringUTF(result);
  }

对于int、double这类数据JNI和C++是可以直接转换使用,那么对于不能直接转换的怎么办呢?肯定会有一些函数的对吧,我们查看刚刚那个JNI中文文档
解读一下这个函数的代码(C++实现)
函数第1行获取Java的string类型数据转化为C++中的字符,JNI函数:env->GetStringUTFChars(j_string, NULL);
接着判断字符串是否==null,据了解,C/C++不会报空指针之类的错误,如果这里为空没有判断,下面代码还是使用会导致很严重问题,比如说你找错找的一脸懵逼,完全不知道哪里的问题,培养严谨的编程习惯,这些一定要判断,(获取接下来的示例中我可能没有写这些判断,不要学我,我只是demo快速写逻辑而已),接下来的代码就是在C++中创建字符,然后转成string类型,将Java传递过来的string字符串和C++的字符串拼接起来再返回出去。这里还要注意:env->ReleaseStringUTFChars( j_string, java_str_char);//释放资源方法,第一行代码获取字符串,这里释放资源,成对使用。
其实如果懂得C++编程的话这里还是很简单的,无非就是如何在C++中创建字符,传唤成为字符串,拼接起来。
C++部分的代码写完了,在Java中调用,代码:

                //模拟Java层调用native基本信息
                msg = mNativeUtils.getStringFromNative(" Java ");
                int nativeInt = mNativeUtils.getIntFromNative(33);
                double nativeDouble = mNativeUtils.getDoubleFromNative(33.33);
                String result = msg + " int: " + nativeInt + " double: " + nativeDouble;
                mtv_text.setText(result);

效果图
这里写图片描述

第二个需求:C++调用Java非静态方法获取基本数据类型(int,double,string)

直接看C++代码

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    nativeCallJavaBaseMsg
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_r_ndk_NativeUtils_nativeCallJavaBaseMsg
   (JNIEnv * env, jobject obj){

    jclass j_class = env->FindClass("com/r/ndk/NativeUtils");
    jobject j_object = env->AllocObject(j_class);

    jmethodID j_method_id1 = env->GetMethodID(j_class, "getStringFromJava","(Ljava/lang/String;)Ljava/lang/String;");
    jmethodID j_method_id2 = env->GetMethodID(j_class, "getDoubleFromJava","(D)D");
    jmethodID j_method_id3 = env->GetMethodID(j_class, "getIntFromJava","(I)I");

    jstring j_str1 = (jstring) env->NewStringUTF(" Native ") ;
    jstring j_str2 = (jstring) env->CallObjectMethod(j_object, j_method_id1,j_str1);//从java层获取string
    jdouble j_double=(jdouble) env->CallDoubleMethod(j_object, j_method_id2,66.66);//从Java层获取double
    jint j_int=(jint) env->CallIntMethod(j_object, j_method_id3,66);//从Java层获取int

    string j_double_str=double2string(j_double);
    string j_int_str=int2string(j_int);
    string tip_int=" int: ";
    string tip_double=" double: ";

    const char * result_string_char = env->GetStringUTFChars(j_str2, NULL);//获取java字符串
    string result_number_str = tip_int + j_int_str + tip_double + j_double_str;//拼接数字
    string result_str = std::string(result_string_char)  + result_number_str;//拼接数字和字符串
    const char* result_char = result_str.c_str();//字符串转换为char
    env->ReleaseStringUTFChars( j_str2, result_string_char);//释放
    return env->NewStringUTF(result_char);
   }

解析:在C++层获取Java数据,首先需要知道要调用的 方法 在哪个 参数 类型等
1.首先获取需要操作的类:env->FindClass(“com/r/ndk/NativeUtils”);
备注:填写类的绝对路径,将 . 换成 /
2.找到需要调用的方法的ID:env->GetMethodID(j_class, “getStringFromJava”,”(Ljava/lang/String;)Ljava/lang/String;”);
备注:第一个参数 类名,第二个参数方法名,第三个参数签名类型
JNI使用Java虚拟机的类型签名表述。下表列出了这些类型签名:
这里写图片描述
例如,Java方法:

long f (int n, String s, int[] arr);

具有以下类型签名:

(ILjava/lang/String;[I)J

特别注意一点:全限定的类后面一定要加 ; 否则开发中遇到运行报错,一脸懵逼不知到什么问题
获取方法ID可以查看JNI中文文档,基本上是:GetMethodID,对于调用静态方法:GetStaticMethodID

3.调用方法:env->CallObjectMethod(j_object, j_method_id1,j_str1);
备注:第一个参数对象,第二个参数方法ID,第三个参数传递的数值(可传多个参数,多种类型的值)
调用方法原型 CallMethod(参数,参数,参数…)type:object,int,double,void ….
静态方法调用:CallStaticObjectMethod(j_class, j_method_id2 ,j_string1); 不同于普通方法,第一个参数需要传class而不是object

这个C++函数主要是介绍这三个方法的使用,其他的逻辑就是,获取到数值转化为string拼接然后返回,很简单的啦。其中有两个方法的代码没有贴上来,是int/double转化为C++字符串的代码,之后在完整的demo中会给出。
Java调用代码:

                //模拟native层调用Java基本数据类型
                msg = mNativeUtils.nativeCallJavaBaseMsg();
                mtv_text.setText(msg);

这个demo在C++层中获取Java的基本数据类型,简单处理一下,再返回给Java展示。

这里写图片描述

到这里基本上实现了C++和Java之间数据的相互调用和传递,接着再实现一下,当C++调用Java之后,Java在处理一下的方法:在C++中传递一个string字符串,Java接收之后Toast提示给用户。(顺便讲解一下C++调用Java静态方法的用例)
看C++代码

/*
 * Class:     com_r_ndk_NativeUtils
 * Method:    nativeCallAndroidToast
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_r_ndk_NativeUtils_nativeCallAndroidToast
  (JNIEnv * env, jobject obj){

    jclass j_class = env->FindClass("com/r/ndk/NativeUtils");
    jobject j_object = env->AllocObject(j_class);

    jmethodID j_method_id1 = env->GetMethodID(j_class, "showToast","(Ljava/lang/String;)V");//获取方法ID
    jmethodID j_method_id2 = env->GetStaticMethodID(j_class, "getStringFromJavaWithStatic","(Ljava/lang/String;)Ljava/lang/String;");//获取静态方法ID
    jstring j_string1=(jstring)env->NewStringUTF(" c++ string ");
    jstring j_string2 = (jstring)env->CallStaticObjectMethod(j_class, j_method_id2 ,j_string1);//调用静态方法
    env->CallVoidMethod(j_object,j_method_id1,j_string2);//调用方法

  }

Java代码

    // 提示信息,提供JNI调用
    public void showToast(String msg) {
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }

Java调用代码

    //模拟native层调用安卓Toast
    mNativeUtils.nativeCallAndroidToast();

效果:
这里写图片描述

嗯,到这里基本上Java和C++之间的相互都过了一遍,对于拓展方面可以参考JNI中文文档进行学习,开发中多少都会遇到坑,多查查资料,解决之后共享出来,一起进步。

源码下载

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用 的相关文章

  • BitmapFactory 解码 BMP 图像

    我在用这段代码 http android developers blogspot com 2010 07 multithreading for performance html从 Android 开发者博客下载 BMP 文件 例如this
  • 通过硬件按钮启动 Android 应用程序

    我希望构建一个在单击特定硬件按钮时启动的 Android 应用程序 例如 当我按下音量增大按钮 30 秒时 应用程序必须在不增加音量的情况下启动 我想知道这可能吗 你可以定义一个BroadcastReceiver处理ACTION MEDIA
  • 在 Java/Android 中检查字符串是否包含 URL 的最佳方法是什么?

    在 Java Android 中检查字符串是否包含 URL 的最佳方法是什么 最好的方法是检查字符串是否包含 com net org info 其他 或者有更好的方法吗 url 输入到 Android 中的 EditText 中 它可以是粘
  • 图像识别后如何在vuforia sdk ImageTarget中显示布局而不是茶壶模型

    如果图像在 qualcomm vuforia sdk 中被识别 我们如何在布局中显示简单的文本 即 Hello 我正在使用 ImageTarget 的 qualcomm vuforia sdk 示例 现在它在识别图像后显示一个茶壶 我是增强
  • 停止在列表视图中滚动

    我的活动中有一个列表视图和一个图像按钮 当我单击图像按钮时 我想转到列表中的特定位置 我通过调用列表上的 setSelection intposition 来实现此目的 当用户滑动列表视图然后单击图像按钮时会出现问题 列表将转到指定位置但继
  • Android 从图库中选择图像显示内存错误

    我正在编写一个代码示例 我必须从图库中选择一个图像 该代码正在运行 但是在从图库中选择图像后 我得到了内存不足错误 in my 活动结果时 我可以获得小图像 但大图像会产生问题 这是我的代码 try Uri selectedImageUri
  • 如何在 PercentRelativeLayout 中使用layout_aspectRatio?

    我尝试在视图上实现 16 9 的纵横比PercentRelativeLayout https developer android com reference android support percent PercentRelativeLa
  • Android Activity 重新创建自身

    我的应用程序通常运行得很好 直到我在特定设备上遇到奇怪的问题 App中有2个活动 当我在 ActivityA 内启动 ActivityB 后 ActivityA 启动时没有问题 但是 当我通过按下硬件按钮或调用 finish 返回 Acti
  • Room - LiveData 观察器在数据库更新时不会触发

    我试图在下面的代码中找出 为什么在我用新数据填充数据库后 Room 的 LiveData observable 不会给我新的转变 这是放在我的活动的 onCreate 方法中 shiftsViewModel ViewModelProvide
  • 如何在Android项目中使用libffmpeg.so?

    我正在尝试在 Android 中创建一个屏幕录制应用程序 为此 我使用 FFmpeg 我已经创建了 libffmpeg so 文件 现在我想在 Android 项目中使用相同的方法来调用它的本机函数 我怎样才能做到这一点 本教程提供了有关此
  • 如何在Android上获取角度中的按键事件?

    我们如何在 Android 上的 Angular 中获取按键事件及其值 我使用phonegap Cordova Angular JS
  • 改造添加带有令牌和 ID 的标头

    我在获取经过身份验证的用户时遇到问题 在此之前我得到了令牌和用户 ID 现在我需要使用访问令牌和 ID 从服务器获取用户 我有标题格式 https i stack imgur com OQ87Y png 现在我尝试使用拦截器添加带有用户令牌
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • Kotlin 中的枚举类对于 Android 来说是否像 Java 中那样“昂贵”?

    Are EnumKotlin 中的类对于 Android 来说 昂贵 就像 Java 一样 还可以用吗 IntDefs or StringDefs在科特林 当我将 Kotlin Enum 类反编译为 Java 类时 底层仍然使用了 Java
  • 如何在Android JUnit测试用例中调用Button.performClick?

    我是 Android 测试方面的新手 我想测试单击按钮是否会打开相应的活动 我做了一些研究 发现我需要使用 ActivityManager 来进行检查 问题是 我无法让 点击 部分正常工作 我正在尝试使用Button performClic
  • Android Studio 1.0 在 dexDebug 或 dexRelease 上构建失败

    我最近从 Android Studio 0 9 2 升级到 1 0 包括 Gradle 插件版本 1 0 0 并且在构建项目时遇到问题 每当我构建时 我都会在 dexDebug 或 dexRelease 步骤中收到以下异常 UNEXPECT
  • 上传失败您应该使用 http 和 https 作为您的 Web 意图过滤器的方案

    上传失败 您应该使用 http 和 https 作为您的 Web 意图过滤器的方案 我在将免安装应用上传到 Play 商店时收到此错误 我在清单中声明了 http 和 https 的意图过滤器 如下所示
  • Android Wear Overlay 传递触摸事件

    我有一个 Android Wear 应用程序 其中我使用透明的覆盖视图来接收触摸事件 我需要能够接收屏幕上任何位置发生的所有触摸事件 并且还能够看到它们的坐标 我发现的所有研究都表明我无法接收所有触摸事件并将其传递 然而 and 都在做这样
  • 如何使用Android Invalidate()

    在我的主要活动中 我定义了两个视图和一个菜单 浏览次数 1 自定义视图游戏 2 按钮btn 菜单 1 打开项目用于打开文件 菜单布局在不同的活动中定义 基本上 当主活动启动时 它会绘制没有任何内容的自定义视图和按钮 然后我使用菜单中的 打开
  • 如何在 Android 上设置 Google Drive API?

    我一直在尝试将 Google Drive 功能集成到我的应用程序中 但我无法使用任何内置功能 因此我相信我要么错过了一个步骤 要么做得不正确 我正在遵循官方的 Google 开发者指南 https developers google com

随机推荐

  • 使用Lattice包进行基础绘图 - R语言

    使用Lattice包进行基础绘图 R语言 Lattice包是R语言中一个强大且灵活的绘图工具 它可以用于创建各种类型的统计图形 在本文中 我们将介绍如何使用Lattice包进行基础绘图 并提供相应的源代码示例 首先 我们需要安装并加载Lat
  • javascript编写自己的模板解析器

    编写自己的模板解析器 因为最近在研究artTemplate ejs baaiduTemplate等模板 所以 一时兴起 自己也写了个简单的模板解析器 一个最基本的模板解析器 需要有什么功能呢 读取变量值 解析模板语句 按照这个思路 我们编写
  • 简单的感知器实现

    什么是感知器 神经网络的组成单元 神经元 神经元也叫感知器 感知器的组成 输入权值 激活函数 输出 感知器的输出公式 y f w x b 下面构建一个简单的感知器 from functools import reduce 1 functoo
  • leetcode—21.二叉树路径和相关题目leetcode总结

    文章目录 引言 112 路径总和 113 路径总和 II 129 求根节点到叶子节点数字之和 124 二叉树中的最大路径和 257 二叉树的所有路径 引言 树的求和属于树的题目中比较常见的 因为可以有几种变体 灵活度比较高 也可以考察到对于
  • C语言二级题库带答案+解析

    1 程序流程图中带有箭头的线段表示的是 A 图元关系 B 数据流 C 控制流 D 调用关系 参考答案 C 解析 在数据流图中 用标有名字的箭头表示数据流 在程序流程图中 用标有名字的箭头表示控制流 所以选择C 2 结构化程序设计的基本原则不
  • STM32单片机基础15——使用硬件I2C读取温湿度传感器数据(SHT30)

    本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设 读取SHT30温湿度传感器的数据并通过串口发送 1 准备工作 硬件准备 开发板 首先需要准备一个开发板 这里我准备的是STM32L4的开发板 Be
  • ant design pro v5 - 07 多标签窗口 多窗口打开

    1 安装组件 安装 yarn add umi plugin keep alive 2 创建模板 src services types menu ts export interface menuTabProps tab string path
  • 百度飞桨PaddlePaddle论文复现训练营——U-GAT-IT 论文复现心得

    项目背景 本次论文复现是源自百度顶会论文复现营 https aistudio baidu com aistudio education group info 1340 复现对象是 2020 ICLR 上的 U GAT IT 这篇论文 htt
  • 整理

    1 前端安全问题有哪些 如何防范 主要有XSS攻击和CSRF攻击 xss 跨站脚本攻击 在网页里植入一段恶意代码 在该网站的作用域下执行了这段代码 防范 1 在服务端设置对cookie的保护 也就是设置httponly 防止用户通过docu
  • IO进程线程day7(2023.8.4)

    一 Xmind整理 二 课上练习 练习1 创建两个线程 其中一个线程拷贝前半部分 另一个线程拷贝后半部分 只允许开一份资源 且用互斥锁方式实现 提示 找临界区 gt 找临界资源 include
  • Python爬虫入门10:select方法快速定位HTML内容

    前往老猿Python博客 https blog csdn net LaoYuanPython 一 引言 在前两节介绍了通过属性和查找方法定位HTML报文的内容的方法 除了这两种方法还有一种方法就是通过使用CSS选择器的语法找到tag 关于c
  • IntelliJ IDEA 2018.3.3版本破解,亲测可用

    一 到官网下载收费版本 如下 二 安装 破解 1 下载http idea lanyus com 标题 2 找到intelliJ IDEA的安装目录的bin目录 然后把下载的JetbrainsIdesCrack 4 2 release sha
  • 逻辑滚动条LVM测试记录1

    逻辑滚动条LVM测试记录 一 由partition或disk到实体滚动条PV的过程 1 划分出系统标示符为8e00的partition gdisk l dev sda命令查看现有分区情况 系统标示符 system ID 指的就是code一项
  • Python缺失值处理

    没有高质量的数据 就没有高质量的数据挖掘结果 数据值缺失是数据分析中经常遇到的问题之一 当缺失比例很小时 可直接对缺失记录进行舍弃或进行手工处理 但在实际数据中 往往缺失数据占有相当的比重 这时如果手工处理非常低效 如果舍弃缺失记录 则会丢
  • 西门子V90伺服驱动器的面板控制

    前言 本文主要讲解一下伺服驱动器的面板控制 大致了解它的功能 一 V90概述 概述 SINAMICS V90是西门子推出的一款小型 高效便捷的伺服系统 它作为 SINAMICS 驱动系列家族的新成员 与SIMOTICS S 1FL6 伺服电
  • 启动Jmeter时遇到的几种错误

    1 权限不够 解决办法 用管理员权限运行 2 sdk版本太低 解决办法 1 查看当前sdk版本 java version 2 安装sdk1 7或以上版本 jmeter3 0版本要用sdk1 7及以上版本 3 配置的环境变量没有生效 在ubu
  • Spring Boot实战之配置使用Logback进行日志记录

    2019独角兽企业重金招聘Python工程师标准 gt gt gt Spring Boot实战之配置使用Logback进行日志记录 在这篇文章中我们将讨论在Spring Boot中使用Logback 在Spring Boot中使用Logba
  • 开源 AI库Stable Diffusion 介绍

    Stable Diffusion 是一个用于生成高质量 AI 绘画的 Python 库 以下是一些使用 Stable Diffusion 的基本步骤 安装 Stable Diffusion 库 您可以使用 pip 安装 命令如下 pip i
  • 性能测试包括哪些方面?

    性能测试 通过自动化测试工具模拟多种正常 峰值 以及异常的负载情况下对系统各项性能指标进行的测试 负载测试 压力测试 容量测试都属于性能测试 性能测试指标是衡量系统性能的评价标准 主要关注一些响应时间 并发用户 并发 点击率 吞吐量 TPS
  • Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用

    前言 一直觉得无论是从行业形式来看 还是从就业角度说 学习JNI NDK开发是一条必经之路 很多说Android和IOS几乎没有市场了 其实只能说现在开发APP的需求没那么多了 再加上之前培训机构疯狂向市场输出Android IOS开发人员