当前位置: 首页 > news >正文

Android JNI基础

目录

  • 一、JNI简介
    • 1.1 什么是JNI
    • 1.2 用途
    • 1.3 优点
  • 二、初探JNI
    • 2.1 新建cpp\cmake
    • 2.2 build.gradle配置
    • 2.3 java层配置
    • 2.4 cmake和c++
  • 三、API详解
    • 3.1 JNI API
      • 3.1.1 数据类型
      • 3.1.2 方法
    • 3.2 CMake脚本
  • 四、再探JNI


一、JNI简介

1.1 什么是JNI

JNI(Java Native Interface)是Java提供的一种机制,用于实现Java和本地(Native)代码之间的交互。通过JNI,Java程序可以调用本地代码(如C、C++)中的函数,实现跨语言的互操作性。

在这里插入图片描述

1.2 用途

JNI主要用于以下几个方面:

调用系统级别的库和函数:可以使用JNI调用操作系统提供的底层功能,如文件操作、网络通信等。
提高性能:通过JNI将性能关键的部分用本地代码实现,可以提高程序的执行效率。
访问硬件资源:JNI可以用于访问硬件资源,如摄像头、传感器等。
调用第三方库:可以使用JNI调用第三方的本地库,以实现更多功能。

1.3 优点

使用JNI具有以下几个优点:

跨语言支持:可以与本地代码(如C、C++)进行无缝交互,扩展了Java的能力。
性能优势:通过JNI可以将性能关键的部分用本地代码实现,提高程序的执行效率。
访问系统资源:可以通过JNI访问系统级别的资源和功能,扩展了Java程序的能力。
调用第三方库:可以利用JNI调用第三方的本地库,扩展了Java程序的功能。
native层的代码往往更加安全,反编译so文件比反编译jar文件要难得多,往往把涉及到密码密钥相关的功能用C/C++实现,然后java层通过jni调用

通过JNI,Java程序可以充分利用本地代码的优势,实现更多功能和性能优化,同时也扩展了Java的应用领域。


二、初探JNI

为了更直接了解JNI,用一个简单的示例先来看一下JNI。

2.1 新建cpp\cmake

使用安卓Studio
在app/src/main文件夹下新建cpp文件夹
在这里插入图片描述

cpp文件夹下新建CMakeLists.txt和native-lib.cpp
在这里插入图片描述

2.2 build.gradle配置

配置模块名称"myjni"和产出的架构平台

  defaultConfig {applicationId "com.henry.basic"namespace "com.henry.basic"......ndk {// 指定库名称moduleName "myjni"// 指定需要产出哪些架构平台abiFilters "arm64-v8a", "armeabi-v7a", "x86", "x86_64"}}

指定CMake脚本路径和版本号

android {compileSdk 34......externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt')version '3.22.1'}}
}

2.3 java层配置

定义一个JNIDemo 类
静态加载myjni 库
native方法返回String字符串,一会在c++层面实现。

public class JNIDemo {static {System.loadLibrary("myjni");}public JNIDemo() {}public native String helloJni();}

static { System.loadLibrary("myjni"); } 会在类被加载到内存中时执行。当首次使用该类时,Java虚拟机会加载并初始化这个类,执行静态代码块中的代码,从而加载本地库 myjni。这确保了在调用任何类方法或创建类实例之前,本地库已经被加载进内存,以便后续的JNI调用可以正常进行。

Launcher中的Activity
在Oncreate中实例化JNIDemo,并调用native方法。

public class jniActivity extends AppCompatActivity {String TAG = "henry";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dialog_test);JNIDemo demo = new JNIDemo();Log.d(TAG, "      : " + demo.helloJni());}}

2.4 cmake和c++

上层和配置已经完成
接下来就剩下c++层面的实现和cmake脚本的编写了。

初学者看到cmake脚本肯定会头大,建议新建工程时选择C++,工程会自动生成Cmake脚本和cpp层面的实现,在此基础上学习Cmake。
在这里插入图片描述
回到我们当前的工程编写c++和Cmake

native-lib.cpp:

#include <jni.h>
#include <string>extern "C"
JNIEXPORT jstring JNICALL
Java_com_henry_cmaketest_JNIDemo_helloJni(JNIEnv *env, jobject thiz) {// TODO: implement helloJni()std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}

1.#include <jni.h>:包含了JNI的头文件,提供了JNI的相关函数和数据结构的定义。
2.#include < string>:包含了C++标准库中的字符串处理相关的头文件。
3.extern “C”:指定了使用C语言的调用约定,确保编译器正确处理函数名。
4.JNIEXPORT jstring JNICALL:定义了本地方法的返回类型为 jstring,表示返回一个Java的字符串对象。JNIEXPORT 和 JNICALL 是JNI的宏定义,用于声明本地方法。
5.Java_com_henry_cmaketest_JNIDemo_helloJni(JNIEnv *env, jobject thiz):实现了一个名为 helloJni 的本地方法,该方法与Java中的 JNIDemo 类中的 helloJni 方法对应。JNIEnv *env 是JNI环境指针,jobject thiz 是Java对象。
std::string hello = “Hello from C++”;:创建一个C++字符串 hello,内容为 “Hello from C++”。
return env->NewStringUTF(hello.c_str());:使用JNI环境指针 env 的 NewStringUTF 方法将C++字符串转换为Java字符串对象,并返回给Java调用方。

CMakeLists.txt

cmake_minimum_required(VERSION 3.22.1)project("myjni")add_library(${CMAKE_PROJECT_NAME} SHARED# List C/C++ source files with relative paths to this CMakeLists.txt.native-lib.cpp)target_link_libraries(${CMAKE_PROJECT_NAME}# List libraries link to the target libraryandroidlog)

1.指定了CMake的最低版本要求为3.22.1
2.定义了项目名称为 “myjni”。
3.添加一个名为 ${CMAKE_PROJECT_NAME} 的共享库,这里会被替换为 “myjni”。共享库类型为 SHARED,表示构建一个共享库。native-lib.cpp 是该共享库的源文件,用于实现JNI的本地方法。
4.将目标库 ${CMAKE_PROJECT_NAME} 与指定的库进行链接。在这里,目标库会链接到 android 库和 log 库。android 库提供了Android平台相关的功能和API,而 log 库用于在Android平台上输出日志。

运行,看一下LOG输出: 正是我们native-lib.cpp里面定义的字符串。
在这里插入图片描述

本地使用Everything搜一下myjni字段:
在这里插入图片描述

打开.bat:
相关命令带一些参数
在这里插入图片描述

打开txt:
先编译cpp文件
然后链接共享库生成libmyjni.so
在这里插入图片描述
打开相关.so所在文件夹:四个架构的so库都已生成。
在这里插入图片描述

三、API详解

初探JNI已经完毕,接下来需要归纳一些知识了,稍微大一点的项目用到的不仅仅是上面的皮毛,比如CMake脚本的各种命令所代表的含义?native-lib.cpp里的JNIEXPORT、jstring 、JNICALL都是什么意思?

3.1 JNI API

上例只是简单的返回了一个字符串,实际上我们还可以做很多事情,jni.h都给我们定义好了标准,我们按照它的标准来即可。
比如,java中叫boolean,jni中叫jboolean,jni给我们提供了若干个映射表,将java中的类型与jni中的类型进行了一 一映射,其中包括基本数据类型映射,引用数据类型映射,方法签名(包含参数和返回值)映射,以下是这三个映射表:

3.1.1 数据类型

基本数据类型映射表
在这里插入图片描述
引用数据类型映射表
在这里插入图片描述
方法签名
在这里插入图片描述
示例

    public native String stringJni();public native float floatJni(int number,Boolean enabled);

对应的native层:

extern "C"
JNIEXPORT jfloat JNICALL
Java_com_henry_cmaketest_JNIDemo_floatJni(JNIEnv *env, jobject thiz, jint number, jobject enabled) {
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_henry_cmaketest_JNIDemo_stringJni(JNIEnv *env, jobject thiz) {
}

顺便讲一下J开头所代表的含义:

符号描述
extern “C”用于指定函数按照 C 的方式进行编译。在 JNI 开发中,由于 JNI 是用 C 语言编写的,因此需要使用 extern “C” 来告诉编译器按照 C 的方式进行编译,以确保函数名不会被 C++ 的名称修饰(name mangling)。
JNIEXPORT这是一个宏定义,用于指示编译器将函数导出为共享库中的一个 JNI 函数。在 JNI 开发中,通常会使用这个宏定义来声明 JNI 函数。
JNICALL这是一个宏定义,用于指示 JNI 函数的调用约定。在 JNI 开发中,通常会使用这个宏定义来声明 JNI 函数的调用约定。
JNIEnv *env这是一个指向 JNI 环境的指针,用于在本地代码中与 Java 虚拟机进行交互。通过 env 可以调用 JNI 提供的函数来获取 Java 对象、调用 Java 方法等操作。
jobject thiz这是一个代表当前对象的引用,通常用于在本地代码中调用 Java 对象的方法。在 JNI 中,thiz 代表当前调用 JNI 函数的 Java 对象。

3.1.2 方法

jni访问调用对象

方法描述
GetObjectClass获取调用对象的类,我们称其为target
FindClass根据类名获取某个类,我们称其为target
IsInstanceOf判断一个类是否为某个类型
IsSamObject是否指向同一个对象

jni访问java成员变量的值

方法描述
GetFieldId根据变量名获取target中成员变量的ID
GetIntField根据变量ID获取int变量的值,对应的还有byte,boolean,long等
SetIntField修改int变量的值,对应的还有byte,boolean,long等

jni访问java静态变量的值

方法描述
GetStaticFieldId根据变量名获取target中静态变量的ID
GetStaticIntField根据变量ID获取int静态变量的值,对应的还有byte,boolean,long等
SetStaticIntField修改int静态变量的值,对应的还有byte,boolean,long等

jni访问java成员方法

方法描述
GetMethodID根据方法名获取target中成员方法的ID
CallVoidMethod执行无返回值成员方法
CallIntMethod执行int返回值成员方法,对应的还有byte,boolean,long等

jni访问java静态方法

方法描述
GetStaticMethodID根据方法名获取target中静态方法的ID
CallStaticVoidMethod执行无返回值静态方法
CallStaticIntMethod执行int返回值静态方法,对应的还有byte,boolean,long等

jni访问java构造方法

方法描述
GetMethodID根据方法名获取target中构造方法的ID,注意,方法名传
NewObject创建对象

jni创建引用

方法描述
NewGlobalRef创建全局引用
NewWeakGlobalRef创建弱全局引用
NewLocalRef创建局部引用
DeleteGlobalRef释放全局对象,引用不主动释放会导致内存泄漏
DeleteLocalRef释放局部对象,引用不主动释放会导致内存泄漏

除此之外,jni还提供了异常处理机制,处理方式跟java一样有两种,要么往上(java层)抛,要么自己捕获处理

方法描述
ExceptionOccurred判断是否有异常发生
ExceptionClear清除异常
Throw往上(java层)抛出异常
ThrowNew往上(java层)抛出自定义异常

以上只是常用API,其他的可以自行到jni.h文件里去查看。

3.2 CMake脚本

CMake编写规则:

CMakeLists会自动创建两个变量,PROJECT_SOURCE_DIRPROJECT_NAME

字段描述示例
cmake_minimum_required指定所需的最低 CMake 版本。cmake_minimum_required(VERSION 3.10)
project定义项目的名称project(MyProject)
PROJECT_SOURCE_DIR本CMakeLists.txt所在的文件夹路径
PROJECT_NAME本CMakeLists.txt的project名称add_library(${CMAKE_PROJECT_NAME} SHARED native-lib.cpp)
add_executable添加可执行文件,指定可执行文件的名称和源文件。add_executable(my_executable main.cpp)
add_library添加库文件,指定库文件的名称和源文件。add_library(my_library my_source.cpp)
target_link_libraries链接库文件到可执行文件或其他库文件。target_link_libraries(my_executable my_library)
include_directories添加头文件搜索路径。include_directories(include)
link_directories添加库文件搜索路径。link_directories(lib)
set设置变量。set(SRC_FILES main.cpp)
if条件判断。if(CONDITION)…endif()
foreach遍历列表。foreach(item IN LISTS LIST_VARIABLE) …endforeach()
message输出消息。message(“Hello, CMake!”)
install安装目标文件到指定目录。install(TARGETS my_executable DESTINATION bin)
find_package查找外部库。find_package(OpenGL REQUIRED)
add_definitions添加编译器选项。add_definitions(-DDEBUG)
add_subdirectory添加子目录。add_subdirectory(subdir)
find_library在 CMake 中用于查找指定的库文件。find_library(VAR name)VAR:指定一个变量,用于存储查找到的库文件的路径。name:要查找的库文件的名称。
set_target_properties用于设置目标的属性。set_target_properties(my_executable PROPERTIES CXX_STANDARD 11)
IMPORTED_LOCATION指定 IMPORTED 目标的位置。set_target_properties(my_library PROPERTIES IMPORTED_LOCATION /path/to/libmylib.so)
log-lib是一个变量,通常用于存储 Android NDK 中日志库的名称target_link_libraries(my_executable ${log-lib})。
loglog 是 Android NDK 中的一个系统库,用于输出日志信息。target_link_libraries(my_executable log) 来链接 log 库。
PROPERTIESPROPERTIES 是用于设置目标属性的关键字 通过 set_target_properties 函数,可以设置目标的各种属性,如编译选项、输出路径等。set_target_properties(my_executable PROPERTIES CXX_STANDARD 11) 设置可执行文件的 C++ 标准为 C++11

四、再探JNI

这一次,多用一些JNI相关知识写一个demo

新建一个test方法,并添加到native-lib.cpp中。
在这里插入图片描述

再新建一个mycpp.cpp文件,activity中新建一个test2()方法,jni实现在mycpp.cpp文件中

CMakeLists.txt中添加mycpp.cpp:

cmake_minimum_required(VERSION 3.22.1)project("myjni")add_library(${CMAKE_PROJECT_NAME} SHARED# List C/C++ source files with relative paths to this CMakeLists.txt.native-lib.cpp mycpp.cpp)target_link_libraries(${CMAKE_PROJECT_NAME}# List libraries link to the target libraryandroidlog)

Activity:

public class jniActivity extends AppCompatActivity {static {System.loadLibrary("myjni");}private int num = 1;String TAG = "henry";private TextView tv;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.jnitest);JNIDemo demo = new JNIDemo();tv = findViewById(R.id.jniview);Log.d(TAG, "      : " + demo.stringJni());tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {test();test2();}});}public native void test();public native void test2();
}

mycpp.cpp:

#include <jni.h>
#include <string>
#include <android/log.h>
#define TAG    "henry"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型extern "C"
JNIEXPORT void JNICALL
Java_com_henry_cmaketest_jniActivity_test2(JNIEnv *env, jobject thiz) {LOGD("-------------new cpp test");
}

native-lib.cpp:

#include <jni.h>
#include <string>
#include <android/log.h>#define TAG    "henry"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型extern "C"
JNIEXPORT jstring JNICALL
Java_com_henry_cmaketest_JNIDemo_stringJni(JNIEnv *env, jobject thiz) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}/*** 参数一:JNIEnv* env表示指向可用JNI函数表的接口指针,所有跟jni相关的操作都需要通过env来完成* 参数二:jobject是调用该方法的java对象,这里是MainActivity调用的,所以thiz代表MainActivity* 方法名:Java_包名_类名_方法名*/
extern "C"
JNIEXPORT void JNICALL
Java_com_henry_cmaketest_jniActivity_test(JNIEnv *env, jobject thiz) {//获取Activity的class对象jclass clazz = env->GetObjectClass(thiz);//获取MainActivity中num变量id/**参数1:MainActivity的class对象参数2:变量名称参数3:变量类型,具体见上《表3-方法签名》**/jfieldID numFieldId = env->GetFieldID(clazz, "num", "I");//根据变量id获取num的值jint oldValue = env->GetIntField(thiz, numFieldId);//将num变量的值+1env->SetIntField(thiz, numFieldId, oldValue + 1);//重新获取num的值jint num = env->GetIntField(thiz, numFieldId);//先获取tv变量idjfieldID tvFieldId = env->GetFieldID(clazz, "tv", "Landroid/widget/TextView;");//根据变量id获取textview对象jobject tvObject = env->GetObjectField(thiz, tvFieldId);//获取textview的class对象jclass tvClass = env->GetObjectClass(tvObject);//获取setText方法ID/**参数1:textview的class对象参数2:方法名称参数3:方法参数类型和返回值类型,具体见上《表3-方法签名》**/jmethodID methodId = env->GetMethodID(tvClass, "setText", "([CII)V");//获取setText所需的参数//先将num转化为jstringchar buf[64];sprintf(buf, "%d", num);jstring pJstring = env->NewStringUTF(buf);const char *value = env->GetStringUTFChars(pJstring, JNI_FALSE);//创建char数组,长度为字符串num的长度jcharArray charArray = env->NewCharArray(strlen(value));//开辟jchar内存空间jchar *pArray = (jchar *) calloc(strlen(value), sizeof(jchar));//将num字符串缓冲到内存空间中for (int i = 0; i < strlen(value); ++i) {*(pArray + i) = *(value + i);}//将缓冲的值写入到上面创建的char数组中env->SetCharArrayRegion(charArray, 0, strlen(value), pArray);//调用setText方法env->CallVoidMethod(tvObject, methodId, charArray, 0, env->GetArrayLength(charArray));//释放资源env->ReleaseCharArrayElements(charArray, env->GetCharArrayElements(charArray, JNI_FALSE), 0);free(pArray);pArray = NULL;
}

看一下效果:
在这里插入图片描述

参考链接:
CMakeLists.txt的超傻瓜手把手教程
JNI 从入门到实践,爆肝万字详解!
基础JNI语法和常见使用

相关文章:

Android JNI基础

目录 一、JNI简介1.1 什么是JNI1.2 用途1.3 优点 二、初探JNI2.1 新建cpp\cmake2.2 build.gradle配置2.3 java层配置2.4 cmake和c 三、API详解3.1 JNI API3.1.1 数据类型3.1.2 方法 3.2 CMake脚本 四、再探JNI 一、JNI简介 1.1 什么是JNI JNI&#xff08;Java Native Interfa…...

裙边挡边带是什么

裙边挡边带&#xff1a;了解其功能与应用 在日常生活和工业生产中&#xff0c;我们经常会遇到各种形状和功能的带子。其中&#xff0c;裙边挡边带是一种特殊类型的带子&#xff0c;它具有独特的结构和功能&#xff0c;被广泛应用于各种场合。本文将介绍裙边挡边带的基本概念、…...

chabot项目介绍

项目介绍 整体的目录如下所示&#xff1a; 上述的项目结构中出了model是必须的外&#xff0c;其他的都可以根据训练的代码参数传入进行调整&#xff0c;有些不需要一定存在data train.pkl:对原始训练语料进行tokenize之后的文件,存储一个list对象&#xff0c;list的每条数据表…...

ChromeOS 中自启动 Fcitx5 和托盘 stalonetray

ChromeOS 更新的飞快&#xff0c;旧文章的方法也老是不好用&#xff0c;找遍了也没找到很好的可以开机自启动 Linux VM 和输入法、托盘的方法。 研究了一下&#xff08;不&#xff0c;是很久&#xff09;&#xff0c;终于找到个丑陋的实现。 方法基于 ChromeOS 123.0.6312.94…...

画图理解JVM相关内容

文章目录 1. JVM视角下&#xff0c;内存划分2. 类内存分布硬核详解1. 获取堆内存参数2. 扫描堆内存&#xff0c;定位实例3. 查看实例所在地址的数据4. 找到实例所指向的类信息的地址5. 查看class信息6. 结论 3. Java的对象创建流程4. 垃圾判别算法4.1 引用计数法4.2 可达性分析…...

Scikit-Learn K均值聚类

Scikit-Learn K均值聚类 1、K均值聚类1.1、K均值聚类及原理1.2、K均值聚类的优缺点1.3、聚类与分类的区别2、Scikit-Learn K均值聚类2.1、Scikit-Learn K均值聚类API2.2、K均值聚类初体验(寻找最佳K)2.3、K均值聚类案例1、K均值聚类 K-均值(K-Means)是一种聚类算法,属于无…...

蓝桥杯 - 受伤的皇后

解题思路&#xff1a; 递归 回溯&#xff08;n皇后问题的变种&#xff09; 在 N 皇后问题的解决方案中&#xff0c;我们是从棋盘的顶部向底部逐行放置皇后的&#xff0c;这意味着在任何给定时间&#xff0c;所有未来的行&#xff08;即当前行之下的所有行&#xff09;都还没…...

AcWing---乌龟棋---线性dp

312. 乌龟棋 - AcWing题库 思路&#xff1a; 原来没有碰到过类似的题&#xff1a; dp数组为思维&#xff1a;dp[i][j][k][r]&#xff0c;分别表示用了i个第一类型卡片&#xff0c;j个第二类型卡片...所到的格子数的最大分数&#xff0c;为啥不用记录乌龟到了哪里呢&#xff1…...

python代码使用过程中使用快捷键注释时报错

1.代码 2.代码报错 3.代码注释后的结果 4. 原因...

go之web框架gin

介绍 Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API&#xff0c;性能要好得多&#xff0c;多亏了 httprouter&#xff0c;速度提高了 40 倍。 如果您需要性能和良好的生产力&#xff0c;您一定会喜欢 Gin。 安装 go get -u github.com/gin-gonic/g…...

SpringBoot 定时任务实践、定时任务按指定时间执行

Q1. springboot怎样创建定时任务&#xff1f; 很显然&#xff0c;人人都知道&#xff0c;Scheduled(cron ".....") Q2. 如上所示创建了定时任务却未能执行是为什么&#xff1f; 如果你的cron确定没写错的话 cron表达式是否合法&#xff0c;可参考此处&#xff0c…...

MYSQL数据库故障排除与优化

目录 MySQL 单实例故障排查 MySQL 主从故障排查 MySQL 优化 MySQL 单实例故障排查 故障现象 1 ERROR 2002 (HY000): Cant connect to local MySQL server through socket /data/mysql/mysql.sock (2) 问题分析&#xff1a;以上这种情况一般都…...

算法-数论-蓝桥杯

算法-数论 1、最大公约数 def gcd(a,b):if b 0:return areturn gcd(b, a%b) # a和b的最大公约数等于b与a mod b 的最大公约数def gcd(a,b):while b ! 0:cur aa bb cur%bpassreturn a欧几里得算法 a可以表示成a kb r&#xff08;a&#xff0c;b&#xff0c;k&#xff0c…...

222.完全二叉树节点个数

给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最左边的若干位置。若最…...

C++中的string类操作详解

引言 针对C中的string&#xff0c;本文主要讲解如何对其进行插入、删除、查找、比较、截断、分割以及与数字之间的相互转换等。 字符串插入 1. append方法 std::string str "hello"; str.append(7, w); // 在末尾添加7个字符w str.append("wwwwwww");…...

Java绘图坐标体系

一、介绍 下图说明了Java坐标系。坐标原点位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标&#xff0c;表示当前位置为水平方向&#xff0c;距离坐标原点x个像素&#xff1b;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐…...

【MATLAB源码-第38期】基于OFDM的块状导频和梳状导频误码率性能对比,以及LS/LMMSE两种信道估计方法以及不同调制方式对比。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 块状导频和梳状导频都是用于无线通信系统中信道估计的方法。 块状导频&#xff1a; 定义&#xff1a; 在频域上&#xff0c;块状导频是连续放置的一组导频符号。这意味着所有的导频符号都集中在一个短的时间段内发送。 优点…...

javaWeb车辆管理系统设计与实现

摘 要 随着经济的日益增长,车辆作为最重要的交通工具,在企事业单位中得以普及,单位的车辆数目已经远远不止简单的几辆,与此同时就产生了车辆资源的合理分配使用问题。 企业车辆管理系统运用现代化的计算机管理手段&#xff0c;不但可以对车辆的使用进行合理的管理&#xff0c;…...

【DM8】间隔分区

是范围分区的一个扩展 如果使用了间隔函数做分区&#xff0c;在数据插入的时候&#xff0c;如果没有合适的分区&#xff0c;数据库会自动创建一个新的分区。 –year往后推两年 SELECT SYSDATE numtoyminterval(2,‘YEAR’); –month往后推两年 SELECT SYSDATE numtoyminterv…...

0基础如何进入IT行业?

目录 0基础如何进入IT行业&#xff1f; 一、学习路径 二、技能培养 三、实践经验 0基础如何进入IT行业&#xff1f; 对于没有任何相关背景知识的人来说&#xff0c;成功进入IT行业可能看起来是一个遥不可及的目标。然而&#xff0c;只要有正确的方法和坚持不懈的努力&#…...

C#将Console写至文件,且文件固定最大长度

参考文章 将C#的Console.Write同步到控制台和log文件输出 业务需求 在生产环境中&#xff0c;控制台窗口不便展示出来。 为了在生产环境中&#xff0c;完整记录控制台应用的输出&#xff0c;选择将其输出到文件中。 但是&#xff0c;一次性存储所有输出的话&#xff0c;文件会…...

《CSS 知识点》仅在文本有省略号时添加 tip 信息

html <div ref"btns" class"btns"><div class"btn" >这是一段很短的文本.</div><div class"btn" >这是一段很短的文本.</div><div class"btn" >这是一段很长的文本.有省略号和tip.<…...

彩虹聚合DNS管理系统v1.0全新发布

聚合DNS管理系统&#xff08;https://github.com/netcccyun/dnsmgr&#xff09;可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&#xff0c;每个用户可分配不同的…...

3.10 Python数据类型转换

Python类型转换&#xff0c;Python数据类型转换函数大全 虽然 Python 是弱类型编程语言&#xff0c;不需要像Java或 C 语言那样还要在使用变量前声明变量的类型&#xff0c;但在一些特定场景中&#xff0c;仍然需要用到类型转换。 比如说&#xff0c;我们想通过使用 print() …...

Kotlin基础学习

Kotlin基础学习主要涵盖安装Kotlin编译器、了解基础语法、学习变量声明、类型推断、函数定义以及控制结构等方面。以下是一个简要的Kotlin基础学习指南&#xff1a; 一、安装Kotlin 首先&#xff0c;你需要从JetBrains的官方网站下载并安装Kotlin编译器。同时&#xff0c;你也…...

配置交换机 SSH 管理和端口安全——实验1:配置交换机基本安全和 SSH管理

实验目的 通过本实验可以掌握&#xff1a; 交换机基本安全配置。SSH 的工作原理和 SSH服务端和客户端的配置。 实验拓扑 交换机基本安全和 SSH管理实验拓扑如图所示。 交换机基本安全和 SSH管理实验拓扑 实验步骤 &#xff08;1&#xff09;配置交换机S1 Switch>enab…...

海山数据库(He3DB)原理剖析:浅析Doris跨源分析能力

Doris湖仓分析背景&#xff1a; Doris多数据源功能演进 Doris的生态近年来围绕湖仓分析做了较多工作&#xff0c;Doris一直在积极拓宽大数据生态的OLAP分析市场&#xff0c;Doris2.0之后为了满足湖仓分析场景&#xff0c;围绕multi-catalog、数据缓存、容错、pipeline资源管理…...

第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组 题解

VP比赛链接 : 数据加载中... - 蓝桥云课 1 . 九进制 转 十进制 直接模拟就好了 #include <iostream> using namespace std; int main() {// 请在此输入您的代码int x 22*92*81*9;cout << x << endl ;return 0; } 2 . 顺子日期 枚举出每个情况即可 : …...

20240324-1-集成学习面试题EnsembleLearning

集成学习面试题 1. 什么是集成学习算法&#xff1f; 集成学习算法是一种优化手段或者策略&#xff0c;将多个较弱的模型集成模型组&#xff0c;一般的弱分类器可以是决策树&#xff0c;SVM&#xff0c;KNN等构成。其中的模型可以单独进行训练&#xff0c;并且它们的预测能以某…...

默克尔(Merkle)树 - 原理及用途

默克尔&#xff08;Merkle&#xff09;树的原理以及用途 引言 在当今数字化时代&#xff0c;确保数据的完整性是至关重要的。默克尔树作为一种高效的数据结构&#xff0c;被广泛应用于网络安全、分布式系统以及加密货币等领域&#xff0c;用于验证大量数据的完整性和一致性 数…...