Android Studio C++/JNI/Kotlin 示例 二

MainActivity.kt

package com.demo.learn1import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivityclass MainActivity : ComponentActivity() {// 加載原生庫init {System.loadLibrary("native_code")}// 聲明原生方法// 數學運算private external fun computeFactorial(n: Int): Intprivate external fun computeFibonacci(n: Int): Int// 字符串處理private external fun reverseString(input: String): Stringprivate external fun countVowels(input: String): Int// 數組處理private external fun sumIntArray(array: IntArray): Int// 復雜對象處理data class User(val name: String, val age: Int)private external fun processUserData(user: User): Stringoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 計算5的階乘和斐波那契數列第10項Log.d("Native", "5! = ${computeFactorial(5)}")Log.d("Native", "fib(10) = ${computeFibonacci(10)}")// 測試字符串反轉和元音計數功能val testStr = "Hello, JNI!"Log.d("Native", "Reversed: ${reverseString(testStr)}")Log.d("Native", "Vowel count: ${countVowels(testStr)}")// 計算數組元素的和val numbers = intArrayOf(1, 2, 3, 4, 5)Log.d("Native", "Array sum: ${sumIntArray(numbers)}")// 創建User對象并傳遞給本地方法處理val user = User("張三", 25)Log.d("Native", processUserData(user))}
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1) #指定 CMake 的最低版本要求(這里是 3.4.1,Android NDK 的常見要求)
set(CMAKE_CXX_STANDARD 11)  # 啟用C++11支持# 定義庫和源文件
add_library( # 設置庫名稱native_code# 設置庫類型為共享庫SHARED# 提供源文件的相對路徑jni_interface.cppmath_operations.cppstring_processor.cppdata_converter.cpp
)# 查找日志庫
find_library( # 設置路徑變量名稱log-lib# 指定CMake要查找的NDK庫名稱log )# 指定庫應該鏈接到的目標庫
target_link_libraries( # 指定目標庫native_code# 將目標庫鏈接到日志庫${log-lib} )

jni_interface.cpp

這段代碼是用C++實現的JNI(Java Native Interface)接口,它連接了Java/Kotlin代碼和本地C++代碼。

#include "jni_interface.h"
#include <jni.h> //JNI核心頭文件,提供與Java交互的所有必要定義
#include <string> //C++標準字符串庫
#include <android/log.h> //Android日志輸出功能
// 包含自定義類頭文件
#include "math_operations.h"
#include "string_processor.h"
#include "data_converter.h"
//定義了日志宏LOGI,方便輸出調試信息
#define LOG_TAG "NativeCode"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" {// 數學運算示例
JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_computeFactorial(JNIEnv* env,jobject /* this */,jint n) {return math_operations::factorial(n);
}JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_computeFibonacci(JNIEnv* env,jobject /* this */,jint n) {return math_operations::fibonacci(n);
}// 字符串處理示例
JNIEXPORT jstring JNICALL
Java_com_demo_learn1_MainActivity_reverseString(JNIEnv* env,jobject /* this */,jstring input) {std::string cppStr = data_converter::convertJavaStringToCpp(env, input);std::string reversed = string_processor::reverseString(cppStr);return env->NewStringUTF(reversed.c_str());
}JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_countVowels(JNIEnv* env,jobject /* this */,jstring input) {std::string cppStr = data_converter::convertJavaStringToCpp(env, input);return string_processor::countVowels(cppStr);
}// 數組處理示例
JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_sumIntArray(JNIEnv* env,jobject /* this */,jintArray array) {std::vector<int> numbers = data_converter::convertJavaArrayToVector(env, array);int sum = 0;for (int num : numbers) {sum += num;}return sum;
}// 復雜對象示例
JNIEXPORT jstring JNICALL
Java_com_demo_learn1_MainActivity_processUserData(JNIEnv* env,jobject /* this */,jobject user) {jclass userClass = env->GetObjectClass(user);// 獲取字段IDjfieldID nameField = env->GetFieldID(userClass, "name", "Ljava/lang/String;");jfieldID ageField = env->GetFieldID(userClass, "age", "I");// 獲取字段值jstring name = (jstring)env->GetObjectField(user, nameField);jint age = env->GetIntField(user, ageField);// 處理數據std::string cppName = data_converter::convertJavaStringToCpp(env, name);std::string processed = "User: " + cppName + ", Age: " + std::to_string(age);// 清理引用env->DeleteLocalRef(name);env->DeleteLocalRef(userClass);return env->NewStringUTF(processed.c_str());
}} // extern "C"

processUserData方法講解

  • 參數

    • JNIEnv* env:JNI環境指針,提供所有JNI功能

    • jobject this:Java中調用該native方法的對象實例(本例未使用)

    • jobject user:傳入的Java User對象

1.獲取Java類信息

jclass userClass = env->GetObjectClass(user);
  • GetObjectClass:獲取傳入Java對象的類對象

  • 返回的jclass是Java中Class<User>的本地表示

  • 這是后續訪問字段和方法的基礎

2. 獲取字段ID

jfieldID nameField = env->GetFieldID(userClass, "name", "Ljava/lang/String;");
jfieldID ageField = env->GetFieldID(userClass, "age", "I");
  • GetFieldID:獲取字段標識符,需要:

    • 類對象(userClass)

    • 字段名("name",?"age")

    • 字段簽名:

      • "Ljava/lang/String;":Java的String類型

      • "I":Java的int類型

  • 字段ID是后續訪問字段的"鑰匙"

3. 獲取字段值

jstring name = (jstring)env->GetObjectField(user, nameField);
jint age = env->GetIntField(user, ageField);
  • GetObjectField:獲取對象類型字段的值(如String)

    • 需要對象實例和字段ID

    • 返回jobject,需要轉型為具體類型(如jstring

  • GetIntField:獲取基本類型int字段的值

    • 直接返回對應的基本類型(jint實際上是int的別名)

4. 數據處理

std::string cppName = data_converter::convertJavaStringToCpp(env, name);
std::string processed = "User: " + cppName + ", Age: " + std::to_string(age);
  • 將Java字符串轉換為C++字符串(使用輔助工具類)

  • 構造新的字符串信息,組合name和age

  • std::to_string:將數字轉換為字符串

5. 資源清理

env->DeleteLocalRef(name);
env->DeleteLocalRef(userClass);
  • DeleteLocalRef:刪除本地引用,防止內存泄漏

  • JNI中的本地引用在函數返回后不會自動釋放

  • 雖然現代JVM通常能處理這些引用,但顯式釋放是良好實踐

6. 返回結果

return env->NewStringUTF(processed.c_str());
  • NewStringUTF:將C字符串(UTF-8)轉換為Java字符串(jstring)

  • 這個返回的jstring會被自動管理,不需要手動釋放

1.?基本類型映射

JNI定義了與Java基本類型對應的C/C++類型:

Java類型JNI類型C/C++類型大小
booleanjbooleanunsigned char8位
bytejbytesigned char8位
charjcharunsigned short16位
shortjshortshort16位
intjintint32位
longjlonglong long64位
floatjfloatfloat32位
doublejdoubledouble64位

2. 理解類型轉換

字符串轉換

Java字符串(jstring)與C/C++字符串的轉換是常見操作:

// Java String → C++ std::string
std::string jstringToStdString(JNIEnv* env, jstring jStr) {if (!jStr) return "";const char* cStr = env->GetStringUTFChars(jStr, nullptr);std::string cppStr(cStr);env->ReleaseStringUTFChars(jStr, cStr);return cppStr;
}// C++ std::string → Java String
jstring stdStringToJstring(JNIEnv* env, const std::string& cppStr) {return env->NewStringUTF(cppStr.c_str());
}

數組轉換

處理Java數組更復雜一些:

// Java int[] → C++ std::vector<int>
std::vector<int> jintArrayToVector(JNIEnv* env, jintArray array) {std::vector<int> result;jsize length = env->GetArrayLength(array);if (length <= 0) return result;jint* elements = env->GetIntArrayElements(array, nullptr);result.assign(elements, elements + length);env->ReleaseIntArrayElements(array, elements, 0);return result;
}// C++ std::vector<int> → Java int[]
jintArray vectorToJintArray(JNIEnv* env, const std::vector<int>& vec) {jintArray result = env->NewIntArray(vec.size());env->SetIntArrayRegion(result, 0, vec.size(), vec.data());return result;
}

3. 內存管理和引用釋放

引用類型

JNI有三種引用類型:

  1. 局部引用(Local Reference)

    • 默認創建的引用

    • 僅在當前native方法有效

    • 方法返回后自動釋放,但應及時手動釋放

  2. 全局引用(Global Reference)

    • 需要顯式創建:env->NewGlobalRef()

    • 跨多個native調用有效

    • 必須顯式釋放:env->DeleteGlobalRef()

  3. 弱全局引用(Weak Global Reference)

    • 類似全局引用但不阻止GC

    • 創建:env->NewWeakGlobalRef()

    • 釋放:env->DeleteWeakGlobalRef()

最佳實踐

JNIEXPORT void JNICALL Java_Example_memoryExample(JNIEnv* env, jobject obj) {// 1. 創建局部引用jclass localClass = env->FindClass("java/lang/String");// 2. 提升為全局引用jclass globalClass = (jclass)env->NewGlobalRef(localClass);// 3. 不再需要局部引用env->DeleteLocalRef(localClass);// ...使用globalClass...// 4. 最后釋放全局引用env->DeleteGlobalRef(globalClass);
}

4. 高級主題

緩存字段ID和方法ID

// 在全局變量中緩存
struct CachedIDs {jclass exampleClass;jmethodID callbackMethod;jfieldID valueField;
};bool cacheIds(JNIEnv* env) {static CachedIDs cached;cached.exampleClass = (jclass)env->NewGlobalRef(env->FindClass("com/example/Example"));cached.callbackMethod = env->GetMethodID(cached.exampleClass, "callback", "(I)V");cached.valueField = env->GetFieldID(cached.exampleClass, "value", "I");return cached.exampleClass && cached.callbackMethod && cached.valueField;
}JNIEXPORT void JNICALL Java_Example_useCachedIds(JNIEnv* env, jobject obj) {static bool cached = cacheIds(env);if (!cached) return;// 使用緩存的IDsjint value = env->GetIntField(obj, cached.valueField);env->CallVoidMethod(obj, cached.callbackMethod, value + 1);
}

多線程注意事項

// 獲取JVM指針以便在其他線程使用
JavaVM* g_jvm = nullptr;JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {g_jvm = vm;return JNI_VERSION_1_6;
}void backgroundThreadFunction() {JNIEnv* env;int status = g_jvm->AttachCurrentThread(&env, nullptr);if (status < 0) {// 處理錯誤return;}// 在這里可以安全使用JNI// ...g_jvm->DetachCurrentThread();
}

math_operations.h

#ifndef LEARN1_MATH_OPERATIONS_H
#define LEARN1_MATH_OPERATIONS_Hclass math_operations {
public:// 聲明為靜態成員函數(可通過類名直接調用)static int factorial(int n);static int fibonacci(int n);static bool isPrime(int num);
};#endif //LEARN1_MATH_OPERATIONS_H

1.頭文件保護宏

#ifndef LEARN1_MATH_OPERATIONS_H
#define LEARN1_MATH_OPERATIONS_H
// ...
#endif

這是防止頭文件被多次包含的標準做法,避免重復定義錯誤。

2.類定義

class math_operations {
public:// ...
};

定義了一個名為math_operations的類,public:表示后續成員都是公開的。

3.靜態成員函數

static int factorial(int n);
static int fibonacci(int n);
static bool isPrime(int num);

這些是靜態成員函數的聲明,特點是:

  1. static關鍵字:表示這些函數是靜態成員函數

    • 屬于類而不是類的實例

    • 可以直接通過類名調用,不需要創建對象實例

    • 不能訪問類的非靜態成員

  2. 函數聲明

    • 只提供了函數原型(返回類型、函數名、參數列表)

    • 沒有函數體實現(通常在對應的.cpp文件中實現)

為什么使用靜態成員函數

  1. 工具類:當函數邏輯不依賴于對象狀態時

  2. 命名空間替代:在C++中可以用來組織相關函數(替代命名空間)

  3. 無需實例化:可以直接調用,使用更方便


math_operations.cpp

#include "math_operations.h"int math_operations::factorial(int n) {if (n <= 1) return 1;return n * factorial(n - 1);
}int math_operations::fibonacci(int n) {if (n <= 1) return n;return fibonacci(n-1) + fibonacci(n-2);
}bool math_operations::isPrime(int num) {if (num <= 1) return false;for (int i = 2; i * i <= num; i++) {if (num % i == 0) return false;}return true;
}
#include "math_operations.h"
  • 作用:包含對應的頭文件,確保函數聲明與定義一致

  • 語法:使用引號""表示從當前目錄或項目目錄查找頭文件

data_converter.h

#ifndef LEARN1_DATA_CONVERTER_H
#define LEARN1_DATA_CONVERTER_H#include <vector>
#include <string>
#include <jni.h>  // 必須包含JNI頭文件class data_converter {
public:static std::vector<int> convertJavaArrayToVector(JNIEnv* env, jintArray array);static std::string convertJavaStringToCpp(JNIEnv* env, jstring jStr);
};#endif //LEARN1_DATA_CONVERTER_H
  • <vector>:提供C++標準向量容器支持

  • <string>:提供C++字符串支持

  • <jni.h>:JNI開發必需的頭文件,定義了Java和本地代碼交互的所有類型和函數

  • JNIEnv* env:JNI環境指針,提供所有JNI函數訪問

data_converter.cpp

#include "data_converter.h"
#include <vector>std::vector<int> data_converter::convertJavaArrayToVector(JNIEnv* env, jintArray array) {std::vector<int> result;jsize length = env->GetArrayLength(array);jint* elements = env->GetIntArrayElements(array, nullptr);result.assign(elements, elements + length);env->ReleaseIntArrayElements(array, elements, 0);return result;
}std::string data_converter::convertJavaStringToCpp(JNIEnv* env, jstring jStr) {const char* cStr = env->GetStringUTFChars(jStr, nullptr);std::string result(cStr);env->ReleaseStringUTFChars(jStr, cStr);return result;
}

1.?convertJavaArrayToVector?方法

功能

將 Java 的?int[]?數組轉換為 C++ 的?std::vector<int>

實現步驟:

  1. 創建空 vectorstd::vector<int> result

  2. 獲取數組長度

    • env->GetArrayLength(array)?獲取 Java 數組的長度

    • jsize?是 JNI 中表示大小的類型

  3. 獲取數組元素指針

    • env->GetIntArrayElements(array, nullptr)?獲取指向 Java 數組內容的指針

    • 第二個參數?nullptr?表示不關心是否復制了數組

  4. 填充 vector

    • result.assign(elements, elements + length)?將 Java 數組內容復制到 vector

  5. 釋放資源

    • env->ReleaseIntArrayElements(array, elements, 0)?釋放獲取的數組指針

    • 參數?0?表示將內容復制回原數組并釋放臨時內存

  6. 返回結果:包含 Java 數組數據的 vector

關鍵點:

  • 必須成對調用?GetIntArrayElements?和?ReleaseIntArrayElements

  • assign?方法高效地將 C 風格數組復制到 vector

  • 最后一個參數?0?可以是:

    • 0:復制回原數組并釋放臨時內存

    • JNI_ABORT:不復制回原數組但釋放內存

    • JNI_COMMIT:復制回原數組但不釋放內存

2.?convertJavaStringToCpp?方法

功能

將 Java 的?String?對象轉換為 C++ 的?std::string

實現步驟:

  1. 獲取 UTF-8 字符指針

    • env->GetStringUTFChars(jStr, nullptr)?獲取指向 Java 字符串 UTF-8 編碼的指針

    • 第二個參數?nullptr?表示不關心是否復制了字符串

  2. 創建 std::string

    • std::string result(cStr)?用獲取的字符指針構造 C++ 字符串

  3. 釋放資源

    • env->ReleaseStringUTFChars(jStr, cStr)?釋放獲取的字符指針

  4. 返回結果:包含 Java 字符串內容的 std::string

關鍵點:

  • 必須成對調用?GetStringUTFChars?和?ReleaseStringUTFChars

  • 使用 UTF-8 編碼轉換,這是 Java 和 C++ 之間最常用的編碼方式

  • 如果 Java 字符串包含非 ASCII 字符,這種方式能正確處理

3. 可能的改進

  1. 添加空指針檢查

    if (!jStr) return std::string();
  2. 錯誤處理增強

    const char* cStr = env->GetStringUTFChars(jStr, nullptr);
    if (!cStr) {// 處理錯誤
    }

string_processor.h

#ifndef LEARN1_STRING_PROCESSOR_H
#define LEARN1_STRING_PROCESSOR_H#include <string>class string_processor {
public:// 1. 字符串反轉static std::string reverseString(const std::string& input);// 2. 統計元音字母數量static int countVowels(const std::string& input);// 3. 凱撒加密(字母位移)static std::string encryptString(const std::string& input, int shift);
};#endif //LEARN1_STRING_PROCESSOR_H
  • const std::string& input:要反轉的字符串(常量引用,避免拷貝)

const std::string&?講解

1. 基本組成解析

可以分解為三個部分:

  1. std::string?- C++標準庫中的字符串類型

  2. &?- 表示這是一個引用

  3. const?- 表示這是一個常量(不可修改)

2. 為什么要使用這種形式

2.1 避免不必要的拷貝
  • 不使用引用void func(std::string str)
    傳遞參數時會創建字符串的完整副本(拷貝構造)

  • 使用引用void func(const std::string& str)
    只傳遞引用(內存地址),不創建副本

2.2 保證原字符串不被修改
  • const限定確保函數內不能修改原字符串

  • 既享受引用的高效,又保證數據安全

2.3 支持臨時對象
  • 可以接受臨時字符串對象(右值)

  • 例如:func("temporary string")

3. 與替代方案的對比

參數形式拷貝開銷可修改原值接受臨時對象備注
std::string副本可修改最安全但效率最低
std::string&可以修改需要非常量左值
const std::string&不可修改最佳平衡方案
std::string_view?(C++17)不可修改現代替代方案

4. 典型使用場景

4.1 作為輸入參數
void printString(const std::string& str) {std::cout << str;  // 只能讀取,不能修改
}
4.2 與STL算法配合
bool contains(const std::string& str, const std::string& substr) {return str.find(substr) != std::string::npos;
}
4.3 類成員函數
class TextProcessor {
public:void process(const std::string& input) {// 處理輸入但不修改它}
};

5. 注意事項

  1. 生命周期管理
    • 引用必須確保指向的對象在函數使用期間有效

    • 不要返回局部變量的const引用

  2. C++17后的替代方案
    • 考慮使用std::string_view作為只讀參數

    • 更輕量級,支持更多類型的字符串數據

  3. 與移動語義的關系
    • 對于需要"奪取"所有權的情況,應使用std::string&&(右值引用)

    • const&會阻止移動語義的應用

  4. NULL問題
    • 不能直接傳遞NULL/nullptr

    • 如果需要可空引用,應使用指針或std::optional

string_processor.cpp

#include "string_processor.h"
#include <algorithm> // 提供std::reverse
#include <string>  // 提供std::stringstd::string string_processor::reverseString(const std::string& input) {std::string reversed = input;std::reverse(reversed.begin(), reversed.end());return reversed;
}int string_processor::countVowels(const std::string& input) {int count = 0;const std::string vowels = "aeiouAEIOU";for (char c : input) {if (vowels.find(c) != std::string::npos) {count++;}}return count;
}std::string string_processor::encryptString(const std::string& input, int shift) {std::string result;for (char c : input) {if (isalpha(c)) {char base = isupper(c) ? 'A' : 'a';c = ((c - base + shift) % 26) + base;}result += c;}return result;
}

結果

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/88896.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/88896.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/88896.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

B樹和B+樹

B樹B樹&#xff0c;?稱多路平衡查找樹&#xff0c;B樹中所被允許的孩?個數的最?值稱為B樹的階&#xff0c;通常?m表示。?棵m階B樹或為空樹&#xff0c;或為滿?如下特性的m叉樹&#xff1a; 1&#xff09;樹中每個結點?多有m棵?樹&#xff0c;即?多含有m-1個關鍵字。 2…

【版本控制】Perforce Helix Core (P4V) 完全入門指南(含虛幻引擎實戰)

目錄引言第一章&#xff1a;認識 Perforce Helix Core1.1 什么是 Perforce&#xff1f;1.2 P4V 是什么&#xff1f;1.3 核心概念速覽1.4 為什么選擇 Perforce&#xff1f;1.5 與 Git 的核心區別本章總結第二章&#xff1a;安裝與配置2.1 安裝原則&#xff1a;先服務端后客戶端2…

LlamaFactory/unsloth Demo

內部叫Tuning-Factory 參數文檔https://llamafactory.readthedocs.io/zh-cn/latest/index.html 高級技巧&#xff0c;如加速&#xff1a;https://llamafactory.readthedocs.io/zh-cn/latest/advanced/acceleration.html 0.環境 conda env list conda remove --name llm --all c…

水務工程中自動化應用:EtherNet/IP轉PROFIBUS DP連接超聲波流量計

在水務工程領域&#xff0c;自動化技術的應用愈發廣泛。隨著工業4.0概念的普及&#xff0c;不同通信協議的設備之間實現高效互聯互通變得尤為關鍵。EtherNet/IP和PROFIBUS DP作為兩種常見的工業通信協議&#xff0c;各有優勢&#xff0c;在實際應用中&#xff0c;常需要將它們進…

網絡協議和基礎通信原理

網絡協議和基礎通信原理是理解互聯網和各種網絡應用的關鍵。讓我用通俗易懂的方式&#xff0c;帶你逐一深入講解這些內容。 一、基礎概念總覽 TCP/IP協議族&#xff1a;互聯網通信的基礎&#xff0c;由一組協議組成&#xff0c;包括TCP、IP、UDP等。HTTP協議&#xff1a;基于T…

T16IZ遙控器教程__遙控器與無人機對頻

文章目錄前言一、準備設備二、對頻步驟總結前言 在使用自組PX4無人機時&#xff0c;有的小伙伴可能會遇到遙控器無法與無人機對頻連接的問題&#xff0c;別擔心&#xff0c;這篇文章會解決它。 一、準備設備 如下圖&#xff0c;無人機信號接收器&#xff0c;與無人機。 遙控器…

pyspark中map算子和flatmap算子

在 PySpark 中&#xff0c;map 和 flatMap 是兩個常用的轉換算子&#xff0c;它們都用于對 RDD&#xff08;彈性分布式數據集&#xff09;或 DataFrame 中的元素進行處理&#xff0c;但處理方式和應用場景有所不同。下面詳細講解它們的用法和適用場景。1. map 算子功能對 RDD 或…

jenkins部署前端vue項目使用Docker+Jenkinsfile方式

文章目錄前言一、前提準備二、準備構建文件三、Jenkins中構建項目總結前言 前面通過jenkinsdocker的方式部署了若依前端vue項目&#xff0c;接下來接著學習使用Jenkinsfile的方式部署前端vue項目。 一、前提準備 已經安裝好centos服務器&#xff0c;并且安裝了jenkins和docke…

Cadence操作說明

一.allegro修改絲印字體大小的方法 1.選擇Edit–>Change&#xff0c;右側彈出Options選項&#xff0c;選擇Class : New subclass Ref Des : Silkscreen_Top&#xff0c;設置Text block&#xff0c;后面的數字代表字號的大小。菜單菜單欄選擇Setup–>Design Parameters&a…

使用Stitch來生成CrypyTrack的app程序

結果&#xff1a; &#x1f9ed; 第一步&#xff1a;訪問 Stitch 平臺 打開網址&#xff1a;stitch.withgoogle.com使用你的 Google 賬號登錄&#xff0c;無需安裝任何軟件 &#x1f9f1; 第二步&#xff1a;選擇設計模式 Stitch 提供兩種模式&#xff1a; 標準模式&#xf…

告別繁瑣:API全生命周期管理的新范式——apiSQL

API&#xff08;應用程序接口&#xff09;是連接數據與服務的生命線&#xff0c;是數字世界的基石。然而&#xff0c;一個高質量API的誕生并非易事&#xff0c;它涉及一個漫長而復雜的全生命周期——從規劃設計到最終退役&#xff0c;每個環節都需要專門的工具和技能&#xff0…

R 語言科研繪圖第 64 期 --- 啞鈴圖

在發表科研論文的過程中&#xff0c;科研繪圖是必不可少的&#xff0c;一張好看的圖形會是文章很大的加分項。 為了便于使用&#xff0c;本系列文章介紹的所有繪圖都已收錄到了 sciRplot 項目中&#xff0c;獲取方式&#xff1a; R 語言科研繪圖模板 --- sciRplothttps://mp.…

基于MaxCompute MaxFrame 汽車自動駕駛數據預處理最佳實踐

一、背景及挑戰在汽車自動駕駛場景中&#xff0c;車端&#xff08;量產車、研采車&#xff09;持續產生并采集海量數據&#xff0c;包括圖片、音視頻、雷達、GPS等內容&#xff0c;這些數據通常以 ROSbag文件形式進行存儲。行業需求&#xff1a;自動駕駛依賴海量多模態數據&…

NLP:RNN文本生成案例分享

本文目錄&#xff1a;一、導入工具包二、數據集三、 構建詞表四、 構建數據集對象五、 構建網絡模型六、 構建訓練函數七、構建預測函數前言&#xff1a;上篇文章講解了RNN&#xff0c;這篇文章分享文本生成任務案例&#xff1a;文本生成是一種常見的自然語言處理任務&#xff…

AI時代的接口自動化優化實踐:如何突破Postman的局限性

編者語&#xff1a;本文作者為某非銀金融測試團隊負責人。其團隊自 2024 年起局部試用 Apipost&#xff0c;目前已在全團隊正式投入使用 。在推進微服務 API 自動化測試的過程中&#xff0c;研發和測試人員常常需要在接口請求中動態構造帶有特定業務規則的數據。我們團隊就遇到…

動態規劃題解_將一個數字表示成冪的和的方案數【LeetCode】

2787. 將一個數字表示成冪的和的方案數 給你兩個正整數 n 和 x 。 請你返回將 n 表示成一些 互不相同 正整數的 x 次冪之和的方案數。換句話說&#xff0c;你需要返回互不相同整數 [n1, n2, ..., nk] 的集合數目&#xff0c;滿足 n n1x n2x ... nkx 。 由于答案可能非常…

C#常用的LinQ方法

LINQ&#xff08;Language Integrated Query&#xff09;是 .NET 中用于處理集合的強大工具&#xff0c;它提供了多種方法來簡化數據查詢和操作。以下是一些常用的 LINQ 方法及其功能&#xff1a;Where: 根據指定的條件篩選集合中的元素。var filteredResults matchResults.Wh…

目標檢測之數據增強

數據翻轉&#xff0c;需要把bbox相應的坐標值也進行交換代碼&#xff1a;import random from torchvision.transforms import functional as Fclass Compose(object):"""組合多個transform函數"""def __init__(self, transforms):self.transform…

DiffDet4SAR——首次將擴散模型用于SAR圖像目標檢測,來自2024 GRSL(ESI高被引1%論文)

一. 論文摘要 合成孔徑雷達&#xff08;SAR&#xff09;圖像中的飛機目標檢測是一項具有挑戰性的任務&#xff0c;由于離散的散射點和嚴重的背景雜波干擾。目前&#xff0c;基于卷積或基于變換的方法不能充分解決這些問題。 本文首次探討了SAR圖像飛機目標檢測的擴散模型&#…

html案例:編寫一個用于發布CSDN文章時,生成有關縮略圖

CSDN博客文章縮略圖生成器起因&#xff1a;之前注意到CSDN可以隨機選取文章縮略圖&#xff0c;但后來這個功能似乎取消了。于是我想調整一下縮略圖的配色方案。html制作界面 界面分上下兩塊區域&#xff0c;上面是參數配置&#xff0c;下面是效果預覽圖。參數配置&#xff1a; …