Android JNI开发从0到1,java调C,C调Java,保姆级教程详解

news2024/12/23 13:22:26

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂,风趣幽默",感觉非常有意思,忍不住分享一下给大家。
👉点击跳转到教程

第一步首先配置Android studio的NDK开发环境,首先在Android studio中下载NDK包

在这里插入图片描述
第二步在local.properties文件中,配置对应的NDK路径
在这里插入图片描述
第三歩,在app目录下的build.gradle文件中的,android{}闭包中,指定CMakeLists.txt路径

// 在android节点下
    // 指定CMakeLists.txt路径
    externalNativeBuild {
        cmake {
            // 在该文件种设置所要编写的c源码位置,以及编译后so文件的名字
            path 'CMakeLists.txt'
        }
    }

在defaultConfig闭包下配置

// 增加cmake控制属性
        externalNativeBuild {
            cmake {
                // 指定编译架构
                abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
            }
        }

在app目录下,指定CmakeLists.txt文件,根据注释进行相应添加

# CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.
#CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
add_library(
      # 设置so文件名称.
       Hello
       # 设置这个so文件为共享.
       SHARED
       # Provides a relative path to your source file(s).
       src/main/jni/Hello.c)
add_library(
        # 设置so文件名称.
        Test
        # 设置这个so文件为共享.
        SHARED
        # Provides a relative path to your source file(s).
        src/main/jni/Test.c)
add_library(
        # 设置so文件名称.
        CCallJava
        # 设置这个so文件为共享.
        SHARED
        # Provides a relative path to your source file(s).
        src/main/jni/CCallJava.c)

# 添加 log 库的链接
target_link_libraries(CCallJava log)
target_link_libraries(Test log)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
       log-lib
       # Specifies the name of the NDK library that
       # you want CMake to locate.
       log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
            # 制定目标库.
            Hello
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )

第四步,首先进行Java代码C代码的操作
1.JNI2.java代码如下

/**
 * @Author: ly
 * @Date: 2023/8/6
 * @Description: java调C代码
 */
public class JNI2 {
    static {
        System.loadLibrary("Test"); //加载动态链接库
    }

    /**
     * 让C代码做加法运算,把结果返回
     * 场景:大量运算,编解码之类的,需要性能很高的情况下,可以用C代码
     *
     * @param x
     * @param y
     * @return
     */
    public native int add(int x, int y);

    /**
     * 从java传入字符串,C代码进行拼接
     *
     * @param s I am from java
     * @return I am from java and I am from c
     */
    public native String sayHello(String s);

    /**
     * 让C代码给每个元素都加上10
     *
     * @param intArray
     * @return
     */
    public native int[] increaseArrayEles(int[] intArray);

    /**
     * 应用:检查密码是否正确,如果正确返回200,否则返回400
     *
     * @param pwd
     * @return
     */
    public native int checkPwd(String pwd);
}

2.根据命令行javah +JNI2的全类名,生成Test.c对应的C代码头文件com_example_jniproject_JNI2.h

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

#ifndef _Included_com_example_jniproject_JNI2
#define _Included_com_example_jniproject_JNI2
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jniproject_JNI2
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_jniproject_JNI2_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_example_jniproject_JNI2
 * Method:    sayHello
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_jniproject_JNI2_sayHello
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_example_jniproject_JNI2
 * Method:    increaseArrayEles
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_com_example_jniproject_JNI2_increaseArrayEles
  (JNIEnv *, jobject, jintArray);

/*
 * Class:     com_example_jniproject_JNI2
 * Method:    checkPwd
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_example_jniproject_JNI2_checkPwd
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

3.根据jni协议,去写对应的c代码,创建Test.c文件,代码如下

//
// Created by DELL on 2023/8/6.
//
#include "com_example_jniproject_JNI2.h"
#include "string.h"
#include <stdlib.h>

#include <android/log.h>

#define TAG "luyu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型


JNIEXPORT char *JNICALL Java_com_example_MyClass_myMethod(JNIEnv *env, jobject obj, jstring jstr) {
    const char *cstr = (*env)->GetStringUTFChars(env, jstr, NULL);

    // 使用 cstr 进行操作,并获取结果(假设结果为 result)

    (*env)->ReleaseStringUTFChars(env, jstr, cstr);

    char *result = (char *) malloc(strlen(cstr) + 1);
    strcpy(result, cstr);

    return result;
}

/**
 * jint:返回值
 * Java_全类名_方法名
 * JNIEnv *env
 */
jint Java_com_example_jniproject_JNI2_add
        (JNIEnv *env, jobject jobj, jint ji, jint jj) {
    int result = ji + jj;
    return result;
};

/**

     * 从java传入字符串,C代码进行拼接
     *
     * @param s I am from java
     * @return I am from java and I am from c
*/

jstring Java_com_example_jniproject_JNI2_sayHello
        (JNIEnv *env, jobject jobj, jstring jstring1) {
    char *fromJava = Java_com_example_MyClass_myMethod(env, jobj, jstring1);
    char *fromC = " and I am from C";
    //拼接函数,拼接后得到的结果放到第一个参数里面
    strcat(fromJava, fromC);//把拼接的结果放在第一个参数里面
    //jstring     (*NewStringUTF)(JNIEnv*, const char*);
    LOGE("fromJava==%s\n", fromJava);
    return (*env)->NewStringUTF(env, fromJava);
};

/**
 * 给每个元素加10
 * 场景:图片处理,颜色矩阵(就是数组),进行数组的处理
 */
jintArray Java_com_example_jniproject_JNI2_increaseArrayEles
        (JNIEnv *env, jobject jobj, jintArray jintArray1) {
    //1.得到数组的长度
    //jsize       (*GetArrayLength)(JNIEnv*, jarray);
    jsize size = (*env)->GetArrayLength(env, jintArray1);
    //2.得到数组的元素
    // jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
    jint *intArray = (*env)->GetIntArrayElements(env, jintArray1,
                                                 JNI_FALSE);//这里传0 false表示 在同一份内存操作,不开辟新的内存
    //3.遍历数组,给每个元素加10
    int i;
    for (i = 0; i < size; i++) {
        *(intArray + i) += 10;
    }
    // 4. 同步修改到 Java 层
    (*env)->ReleaseIntArrayElements(env, jintArray1, intArray, 0);
    //4.返回结果
    return jintArray1;
};

/**
 * 应用:检查密码是否正确,如果正确返回200,否则返回400
 */
jint Java_com_example_jniproject_JNI2_checkPwd
        (JNIEnv *env, jobject jobj, jstring jstring1) {
    //假设服务器的密码是123456
    char *origin = "123456";
    char *fromUser = Java_com_example_MyClass_myMethod(env, jobj, jstring1);
    //函数比较字符串是否相同
    int code = strcmp(origin, fromUser);
    LOGE("code==%d\n", code);
    if (code == 0) {
        return 200;
    } else {
        return 400;
    }
};

第五步,C代码调用Java代码,首先创建JNI3.java

/**
 * @Author: ly
 * @Date: 2023/8/6
 * @Description: C代码调用Java代码
 */
public class JNI3 {
    static {
        System.loadLibrary("CCallJava"); //加载动态链接库
    }
    //当执行这个方法的时候,让C代码调用
    //public int add(int x, int y)
    public native void callbackAdd();

    /**
     * 当执行这个方法的时候,让C代码调用
     * public void helloFromJava()
     */
    public native void callbackHelloFromJava();

    /**
     * 当执行这个方法的时候,让C代码调用
     * public void printString(String s)
     */
    public native void callbackPrintString();

    /**
     * 当执行这个方法的时候,让C代码调用
     * public static void sayHello(String s)
     */
    public native void callbackSayHello();

    public int add(int x, int y) {
        Log.e("TAG", "add()  x=" + x + " y=" + y);
        return x + y;
    }

    public void helloFromJava() {
        Log.e("TAG", "helloFromJava");
    }

    public void printString(String s) {
        Log.e("TAG", "C中输入的:" + s);
    }

    public static void sayHello(String s) {
        Log.e("TAG", "我是java代码中的JNI" +
                ".java中的sayHello(String s)静态方法,我被C调用了:" + s);
    }
}

2.根据命令行,javah +JNI3全类名,生成CCallJava.c对应的头文件
com_example_jniproject_JNI3.h

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

#ifndef _Included_com_example_jniproject_JNI3
#define _Included_com_example_jniproject_JNI3
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jniproject_JNI3
 * Method:    callbackAdd
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackAdd
  (JNIEnv *, jobject);

/*
 * Class:     com_example_jniproject_JNI3
 * Method:    callbackHelloFromJava
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackHelloFromJava
  (JNIEnv *, jobject);

/*
 * Class:     com_example_jniproject_JNI3
 * Method:    callbackPrintString
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackPrintString
  (JNIEnv *, jobject);

/*
 * Class:     com_example_jniproject_JNI3
 * Method:    callbackSayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackSayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

3.对应的CCallJava.c文件中的代码如下

//
// Created by DELL on 2023/8/6.
//
#include "com_example_jniproject_JNI3.h"
#include <stdlib.h>
#include <stdio.h>

#include <android/log.h>

#define TAG "luyu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型


/**
 * 让C代码调用Java中JNI类的public int add(int x ,int y)
 */
JNIEXPORT void Java_com_example_jniproject_JNI3_callbackAdd(JNIEnv *env, jobject jobj) {
    //1.得到字节码
    //jclass      (*FindClass)(JNIEnv*, const char*);
    jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");
    //2.得到方法
    //jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    //最后一个参数是方法签名
    jmethodID jmethodId = (*env)->GetMethodID(env, jclazz, "add", "(II)I");
    //3.实例化该类
    jobject jobject1 = (*env)->AllocObject(env, jclazz);
    //4.调用方法
    //jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    jint value = (*env)->CallIntMethod(env, jobject1, jmethodId, 99, 1);
    //成功调用
    LOGE("value==%d\n", value);
};

/***
 * 让C代码调用
 * public void helloFromJava()
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackHelloFromJava
        (JNIEnv *env, jobject jobj) {
    //1.得到字节码
    //jclass      (*FindClass)(JNIEnv*, const char*);
    jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");
    //2.得到方法
    //jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    //最后一个参数是方法签名
    jmethodID jmethodIds = (*env)->GetMethodID(env, jclazz, "helloFromJava", "()V");
    //3.实例化该类
    jobject jobject1 = (*env)->AllocObject(env, jclazz);
    //4.调用方法
    //jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallVoidMethod(env, jobject1, jmethodIds);
};

/***
 * 让C代码调用
 * public void printString(String s)
 *
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackPrintString
        (JNIEnv *env, jobject jobj) {
    //1.得到字节码
    //jclass      (*FindClass)(JNIEnv*, const char*);
    jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");
    //2.得到方法
    //jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    //最后一个参数是方法签名
    jmethodID jmethodIds = (*env)->GetMethodID(env, jclazz, "printString", "(Ljava/lang/String;)V");
    //3.实例化该类
    jobject jobject1 = (*env)->AllocObject(env, jclazz);
    //4.调用方法
    //jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    // jstring     (*NewStringUTF)(JNIEnv*, const char*);
    jstring jst = (**env).NewStringUTF(env, "I am Android!");
    (*env)->CallVoidMethod(env, jobject1, jmethodIds, jst);
};

/**
 * 让C代码调用
 * public static void sayHello(String s)
 *
 */
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackSayHello
        (JNIEnv *env, jobject jobj){
    //1.得到字节码
    //jclass      (*FindClass)(JNIEnv*, const char*);
    jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");
    //2.得到方法
    // jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
    //最后一个参数是方法签名
    jmethodID jmethodIds = (*env)->GetStaticMethodID(env, jclazz, "sayHello", "(Ljava/lang/String;)V");
    jstring jst = (**env).NewStringUTF(env, "I am Android!");
    (*env)->CallStaticVoidMethod(env,jclazz,jmethodIds,jst);
};

之后,在MainActivity中调用对应的方法即可

public class MainActivity extends AppCompatActivity {
    private JNI2 jin2;
    private static final String TAG = "MainActivity";
    private JNI3 mJNI3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        jin2 = new JNI2();
        mJNI3 = new JNI3();
    }

    /******以下是Java代码调用C*****/
    public void checkPwd(View view) {
        int result = jin2.checkPwd("12345678");
        Log.i(TAG, "result==" + result);
    }

    public void increaseArrayEles(View view) {
        int array[] = {1, 2, 3, 4};
        jin2.increaseArrayEles(array);
        for (int i = 0; i < array.length; i++) {
            Log.i(TAG, "result[" + i + "]:" + array[i]);
        }
    }

    public void sayHello(View view) {
        String result = jin2.sayHello("I am from java");
        Log.i(TAG, "result==" + result);
    }

    public void add(View view) {
        int result = jin2.add(99, 1);
        Log.i(TAG, "result==" + result);
    }

    /******以下是C调Java代码*****/
    public void callbackAdd(View view) {
        mJNI3.callbackAdd();
    }

    public void callbackHelloFromJava(View view) {
        mJNI3.callbackHelloFromJava();
    }

    public void callbackPrintString(View view) {
        mJNI3.callbackPrintString();
    }

    public void callbackSayHello(View view) {
        mJNI3.callbackSayHello();
    }
}

点击按钮便可输出对应的日志,表示调用成功。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/868874.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT-基于Buildroot构建系统镜像下实现QT开发

QT-基于Buildroot构建系统镜像下实现QT开发 BuildRootUboot的仓库地址和commit idKernel 的仓库地址和commit id BuildRoot已编译库在Windows上的Create上创建项目编译QT项目 BuildRoot 这部分按照100ask官网的教程走即可: Uboot的仓库地址和commit id https://e.coding.net/…

如何使用ChatGPT设计LOGO,只需知道品牌名字就能完成傻瓜式操作

​独特且引人注目的LOGO对于引导用户/消费者快速识别并与你建立联系至关重要。然而&#xff0c;聘请专业的设计师来创建个性化LOGO可能非常昂贵。这里可以使用使用ChatGPT。[1] 你只需要&#xff1a; 准备好公司名称&#xff1b; 能用ChatGPT&#xff0c;用来给BingChat喂log…

WebAPIs 第一天

1.声明变量const优先&#xff08;补充&#xff09; 2.WebAPI基本认知 作用和分类 DOM树和DOM对象 3.获取DOM元素 4.DOM修改元素内容 5.操作元素属性 6.定时器-间歇函数 一.声明变量const优先 ① 变量声明有var let const ② 建议const优先&#xff0c;尽量使用const…

【枚举+推式子】牛客小白月赛 63 E

登录—专业IT笔试面试备考平台_牛客网 题意&#xff1a; 思路&#xff1a; 首先是个计数问题&#xff0c;考虑组合数学 组合数学就是在考虑枚举所有包含1和n的区间 这个典中典就是枚举1和n的位置然后算贡献 双指针超时&#xff0c;考虑推式子&#xff1a; Code&#xff1a…

分类过程中的一种遮挡现象

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;让A&#xff0c;B中各有3个点&#xff0c;且不重合&#xff0c;统计迭代次数并排序。 其中有10组数据 差值结构 迭代次数 构造平均列A 构造平均列AB…

C++笔记之函数参数列表中设置默认值

C笔记之函数参数列表中设置默认值 code review! 代码 #include <iostream>// 函数声明时设置默认值 void printInfo(std::string name "Unknown", int age 0);int main() {printInfo(); // 使用默认参数值printInfo("Alice", 25);…

Scractch3.0_Arduino_ESP32_学习随记_蓝牙鼠标(四)

蓝牙鼠标 目的器材程序联系我们 目的 通过C02实现蓝牙鼠标。 器材 硬件: 齐护机器人C02 购买地址 软件:scratch3.0 下载地址:官网下载 程序 蓝牙鼠标使用使用ESP32自带的BLE蓝牙&#xff0c;不需要再外接模块。可以实现鼠标移动&#xff0c;左右键的点击动作。 联系我们…

C++进阶 智能指针

本篇博客简介&#xff1a;介绍C中的智能指针 智能指针 为什么会存在智能指针内存泄露内存泄漏定义内存泄漏的危害如何检测内存泄漏如何避免内存泄漏 智能指针的使用及其原理RAII设计一个智能指针C官方的智能指针 定制删除器智能指针总结 为什么会存在智能指针 我们首先来看下面…

消息队列(11) - 通信协议的设计

目录 通信协议设计代码实现 通信协议设计 对于我们客户端与服务器之间的通信协议我们约定如下&#xff1a; 具体的协议设计: 之后我们传递的参数也是这些 关于 type其实是在描述当前这个请求 、 响应是在调用那个API 约定如下 对于channel ,是tcp链接中的一个逻辑上的链接,…

Python实现图片文本支持中文,自定义字体

Python实现图片文本支持中文&#xff0c;自定义字体 # 支持中文 import matplotlib #用下载好的字体文件设置字体&#xff0c;从而正确显示中文 myfont matplotlib.font_manager.FontProperties(fnamer"./simsun.ttc") # 自定义的字体文件 plt.figure(figsize (1…

udp一般不会存在错数据

UDP在传输过程中会出现丢包的情况&#xff0c;但不会导致数据错乱的情况&#xff0c;这涉及到UDP协议的特性和工作原理。 无连接性&#xff1a;UDP是一种无连接的传输协议&#xff0c;每个UDP数据包都是独立的&#xff0c;没有依赖关系。因此&#xff0c;即使发生数据包丢失&am…

Golang 局部变量、全局变量 声明

文章目录 一、局部变量二、全局变量 一、局部变量 四种声明方式 多变量声明&#xff1a; package mainimport "fmt"//局部变量声明 func main() {//方法一: 声明一个变量和数据类型&#xff0c;不初始化值&#xff1b;默认值为0&#xff1b;var lvA intfmt.Printl…

圆圈中最后剩下的数字——剑指 Offer 62

文章目录 题目描述解法一题目描述 解法一 class Solution

Spring MVC静态资源映射

Spring MVC静态资源映射 静态资源映射。使用容器的默认Servletlocationmapping&#xff1a;cache-periodorder Spring MVC需要对RESTful风格的URL提供支持&#xff0c;而真正的RESTful风格的URL不应该带有任何后缀&#xff0c;因此将Spring MVC拦截的URL改为“/”&#xff08;正…

使用蓝牙外设却不小心把台式机电脑蓝牙关了

起因 今天犯了一个贼SB的错误&#xff0c;起因是蓝牙键盘突然就不能输入了&#xff08;虽然是连接状态&#xff0c;但是按什么键都没有反应&#xff09; 原来我的解决方法就是重启一下电脑&#xff0c;但是那会电脑开了贼多的软件。我就想重启也太麻烦了&#xff0c;既然重启…

Java之继承

继承 继承为什么使用继承继承是什么继承的语法访问父类成员访问父类成员变量访问父类成员方法 super关键字子类构造方法super和this异同分别的使用方法 继承的方式final关键字 作者简介&#xff1a; zoro-1&#xff0c;目前大一&#xff0c;正在学习Java&#xff0c;数据结构等…

【算法挨揍日记】day02——双指针算法_快乐数、盛最多水的容器

202. 快乐数 202. 快乐数https://leetcode.cn/problems/happy-number/ 题目&#xff1a; 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个…

Python接口自动化之request请求封装

我们在做自动化测试的时候&#xff0c;大家都是希望自己写的代码越简洁越好&#xff0c;代码重复量越少越好。那么&#xff0c;我们可以考虑将request的请求类型&#xff08;如&#xff1a;Get、Post、Delect请求&#xff09;都封装起来。这样&#xff0c;我们在编写用例的时候…

OptaPlanner笔记2

1.5.3 使用maven 修改pom.xml 导入optaplanner-bom以避免为每一个依赖项重复添加版本号 <project>...<dependencyManagement><dependencies><dependency><groupId>org.optaplanner</groupId><artifactId>optaplanner-bom</art…

使用 CycleGAN 进行图像到图像转换

介绍 在人工智能和计算机视觉领域,CycleGAN 是一项非凡的创新,它重新定义了我们感知和操作图像的方式。这种尖端技术彻底改变了图像到图像的转换,实现了领域之间的无缝转换,例如将马变成斑马或将夏日风景变成雪景。在本文中,我们将揭开 CycleGAN 的魔力,并探索其在各个领…