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

Android JNI的理解与使用。

写在前面:Java相对于C/C++来说是更高级的语言,隐藏了指针,可读性更高,更容易学习,但是无法直接操作硬件、运行速度较慢也是不可回避的硬伤。JNI就是Java官方定义的一套标准“接口”,用于Java和C/C++之间互相调用,注意这里是互相调用,而不是只能用Java去调用C/C++。搞Android开发的,JNI是必须掌握的技术,以前我一直逃避,因为觉得比较难,但是真正学习下来并没有那么难。Java运行速度较慢,有一些对时间要求超高的场景,就必须用到JNI。
每一节文末会附上Demo APP的GitHub链接。

  在正式使用JNI之前,我们必须搞清楚两个相关的概念:
  Android NDK:这是Google官方提供的工具包,用于将C/C++代码链接它所需要的库,编译成.so或者.a文件。大白话说就是:没有它就不能在Android Studio 这个应用里面编译C/C++代码。
  JNI:JNI不是包含于Android NDK里面的,两者相互独立,JNI只要是Java代码都能使用,不局限于Android应用开发,很多人容易把两者混为一潭。
  下面开始介绍Android应用中如何使用JNI,以Java调用C/C++这种形式为例子,分两种情况:1、一开始就创建为C/C++项目;2、创建的是一般项目,开发中途想调用C/C++代码。

一、C/C++项目

1.1、创建一个Native C++项目

  在new一个项目的时候,选择Native C++,创建一个名为JNI的项目。
在这里插入图片描述
  创建完之后的项目结构如下:可以看到在java的同级目录,Android Studio已经自动为我们生成了cpp目录,cpp目录下自动生成了cpp文件和CMakeLists文件。
在这里插入图片描述

1.2 CMakeLists.txt 讲解

   CMakeLists的作用就是告诉Android NDK,这个CPP项目的源文件是哪些,需要链接哪些库,需要生成静态库还是动态库。自动生成的 CMakeLists.txt 如下:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("jni")# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED# List C/C++ source files with relative paths to this CMakeLists.txt.native-lib.cpp)# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}# List libraries link to the target libraryandroidlog)

  cmake_minimum_required:用来说明现在使用的CMake的最低版本。
  project(“jni”):告诉NDK这个CMake的项目名称叫jni,与后续编译关系不大,有点吉祥物的意思。
  add_library:这里其实是分三段来看——》${CMAKE_PROJECT_NAME}是规定最后编译产物的名字,这里直接用了上一步的project name jni,也就是说最后编译出来的库名字为 libjni,当然你也可以取其它任意名字,比如Xusu这样。——》SHARED 告诉NDK最后编译的是动态库,生成的是libjni.so,如果需要生成静态库把SHARED更换为STATIC即可,最后生成 libjni.a文件。——》native-lib.cpp 是告诉NDK 需要编译的源文件,这里可以列出来很多个.cpp文件或者.h头文件,每个文件占一行。
  target_link_libraries:意思就是将NDK中现成的android库、log库链接到生成的libjni库中,链接到 android 库可以让你的 C/C++ 代码调用一些底层的 Android API,链接到 log 库就是为了打印日志嘛。写法也是固定的target_link_libraries(target_name library1 library2 …)。

1.3 native-lib.cpp 讲解

  自动生成的native-lib.cpp如下:

#include <jni.h>
#include <string>extern "C" JNIEXPORT jstring JNICALL
Java_com_htc_jni_MainActivity_stringFromJNI(JNIEnv* env,jobject thiz) {std::string hello = "Hello from C++"; /*声明一个字符串*/return env->NewStringUTF(hello.c_str()); /*将C语言中的字符通过.c_str()和NewStringUTF方法传化为Java中的String返回给Java代码使用*/
}

  这里我们贴出MainActivity中声明的方法一起对照更容易理解:

package com.htc.jni;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.widget.TextView;import com.htc.jni.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity {// Used to load the 'jni' library on application startup.static { //固定写法,通过System.loadLibrary加载需要的C/C++动态库System.loadLibrary("jni");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI());}/*** A native method that is implemented by the 'jni' native library,* which is packaged with this application.*/public native String stringFromJNI();
}

  可以看到我们在java代码中通过System.loadLibrary(“jni”) 去加载了libjni.so库,这是JNI的固定写法,然后我们用public native String stringFromJNI()声明了一个JNI方法,并通过tv.setText(stringFromJNI())去调用了它,Java声明JNI方法一定要用native修饰,这也是固定写法。
  我们回到native-lib.cpp,开始就是常规的include头文件不用说,从extern "C"开始说:
  extern “C”:是为了确保NDK按照 C 语言的方式来处理函数名称。C++ 和 C 语言在编译时对函数名称的处理方式有所不同,C++ 会进行名称修饰(name mangling),而 C 不会。下面举个例子——》如果没有 extern “C”,C++ 编译器会对函数名进行名称修饰,编译器会把函数名 Java_com_example_myapp_MainActivity_stringFromJNI 转换为一个复杂的符号,比如:_ZN12MainActivity13stringFromJNIEv 。 这就是 C++ 的名称修饰。Java 层的 JNI 机制无法识别这个符号,会导致无法正确调用该方法。
  JNIEXPORT jstring JNICALL:JNIEXPORT 、JNICALL都是固定写法,它们中间夹着的jstring 是函数的返回值,还记得我们之前声明的native函数吗?public native String stringFromJNI() 这里的jstring对应的就是java中的String。JNI为了实现java和C/C++的通信,规定了一套基本数据类型的对照表:
在这里插入图片描述
  Java_com_htc_jni_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz):这个是stringFromJNI对应的JNI函数的名称,Java_是固定前缀,com_htc_jni_MainActivity_stringFromJNI是Java中声明的native方法所在的包名+类名+native方法名的组合,组合的顺序也是固定的。方法参数有两个JNIEnv* env, jobject,这里有同学就会问了,我们Java里声明的native方法明明没有参数,怎么这里有参数??public native String stringFromJNI() 是没参数,所以这里的JNIEnv* env, jobject thiz其实固定写法,JNIEnv* env代表的是Java环境,后续可以通过env创建Java中的数据对象,访问Java中的函数,jobect thiz表示调用这个方法的 Java 对象实例,在这个例子中指的就是MainActivity,如果声明成静态方法 public static native String stringFromJNI() ,jobject就需要更换成 jclass

1.4 总结

  如果从一开始就创建一个Native C++ 项目,Android Studio会帮我们把JNI需要的环境和文件都准备好,我们只需要学习它的语法即可,其中有几个需要关注的点:1、cpp目录和java目录是同级。2、Java代码中通过System.loadLibrary加载so动态库、通过native关键字声明JNI方法。3、cpp文件JNI方法的命名规则和参数规范。

点击下载Native C++项目Demo:https://github.com/xuhao120833/JN

二、一般的项目,中途想使用C/C++代码

  上面我们讲了用Android Studio创建一般的Native C++项目,Android Studio 已经帮我们做好了准备工作,那么我们APP开发到一半,突然加了个需求对时效性要求很高,必须用C/C++实现,这个时候项目肯定不能推倒重来了,那怎么办???按下面的操作即可:

2.1 自己创建cpp目录和相关文件

  选中main目录按右键,在java的同级目录创建cpp目录:
在这里插入图片描述
  自己创建CMakeLists.txt、编写用到的cpp文件和头文件:
在这里插入图片描述
  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.cmake_minimum_required(VERSION 3.10.2)   #说明CMake的最低要求版本# Declares and names the project.project("Xctouch")  #CMake项目名称取为Xctouch,随意取的# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.add_library( # Sets the name of the library.PxScale     #最后生成的库的名字取为PxScale# Sets the library as a shared library.SHARED      #设置最后生成库为动态库,即.so文件# Provides a relative path to your source file(s).scdefine.h   #列出所有的cpp文件和头文件,每个文件占一行jz_scale.cpptp_savedata_check.cppscJNIfun.cpp)# 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    #找到NDK里面现成的log库,并给它取一个别名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.  #将log库链接到最后生成的libPxScale.so库中PxScale# Links the target library to the log library# included in the NDK.${log-lib} )

  scJNIfun.cpp的文件内容如下:定义了三个方法,前两个相对复杂一些,extern 导入了两个其它cpp文件的方法。

#include <jni.h>
#include <string>
#include <android/log.h>
#include <linux/agpgart.h>
#include "scdefine.h"JNIEXPORT///
extern void ratio_tra_point(int *pRet, int *px4, int *py4, int oldRatio, int newRatio, float scale, int w, int h);
extern int check_bd_data(char *pBuf);
xtouch/////该方法的功能是将 Java 层的两个 int[] 数组(px4 和 py4)传递到 C++ 层,经过 ratio_tra_point 函数处理后,返回一个计算结果数组。
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_htc_server_PxScale_getpxRatioxy(JNIEnv *env, jobject thiz, jintArray px4, jintArray py4, jint oldRatio, jint newRatio, jfloat scale, jint w, jint h) {jintArray intArray = env->NewIntArray(20);jint *intdata = env->GetIntArrayElements(intArray, NULL);jint *tpx4 = NULL;jint *tpy4 = NULL;if(px4!=NULL){tpx4 = (jint *) env->GetIntArrayElements(px4, 0);}else{tpx4 = NULL;}if(py4!=NULL){tpy4 = (jint *) env->GetIntArrayElements(py4, 0);}else{tpy4 = NULL;}LOGD("CPP: Java_com_htc_server_PxScale_getpxRatioxy");memset(intdata,0,sizeof(int)*20);ratio_tra_point(intdata, tpx4, tpy4, oldRatio,newRatio, scale, w, h);env->ReleaseIntArrayElements(intArray, intdata, 0);return intArray;
}//Java 层接收一个字符串,将其进行字符过滤(只保留字母和数字),然后调用 check_bd_data 函数对过滤后的数据进行进一步处理,最终返回一个整型结果。
extern "C"
JNIEXPORT jint JNICALL
Java_com_htc_server_PxScale_checkbddata(JNIEnv *env, jobject thiz, jstring data) {jint ret = 0;int i;char c,checkbuf[2048];const char *str;//LOGD("CPP: Java_com_htc_server_PxScale_checkbddata");str = env->GetStringUTFChars(data, NULL);if(str == NULL){return 0;}else{memset(checkbuf, 0, 2048);for(i=0;i<2048;i++){c = str[i];if((c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z')){checkbuf[i] = c;}else{break;}}ret = check_bd_data(checkbuf);}return ret;
}extern "C"
JNIEXPORT jstring JNICALL
Java_com_htc_server_PxScale_sayHello(JNIEnv* env,jobject thiz) {// 创建 C++ 字符串std::string message = "I'm JNI, Hello Java.";// 返回一个 Java 字符串(jstring)return env->NewStringUTF(message.c_str());
}

2.2 java目录下创建PxScale.java文件

在这里插入图片描述

package com.htc.server;public class PxScale {static {System.loadLibrary("PxScale");}/*** A native method that is implemented by the 'duRYXtp' native library,* which is packaged with this application.**/public native int[] getpxRatioxy(int[] px4, int[] py4, int oldRatio, int newRatio, float scale, int w, int h);public native int checkbddata(String data);public native String sayHello();
}

2.3 build.gradle下添加NDK、JNI配置

  我们需要手动指定CMakeLists.txt的位置和版本、ndk的版本、ndk最后编译产物的信息。
  defaultConfig标签范围内添加如下标签信息:

		externalNativeBuild {cmake {cppFlags ""}}ndk {ldLibs "log"moduleName "PxScale"                   //生成的so名字。abiFilters "arm64-v8a", "armeabi-v7a"  //输出指定abi体系结构下的so库。}

  android标签范围内添加如下标签信息:

	externalNativeBuild {cmake {path "src/main/cpp/CMakeLists.txt"  //指定CMakeLists的绝对路径。version "3.10.2"                    //指定CMake的版本。}}ndkVersion '21.0.6113669'                   //指定ndk的版本。

注意:build.gradle中不要打开代码混淆开关,打开会导致Java函数可以找到C/C++函数,但是C/C++函数执行完毕返回值给Java函数的时候找不到Java函数,导致执行报错。解决办法暂时未知。

buildTypes {release {minifyEnabled false  //true混淆打开//zipAlignEnabled true  //优化代码//shrinkResources true  //优化资源proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}

2.4 MainActivity调用JNI测试

  MainActivity的代码如下:

package com.htc.server;import android.os.Bundle;
import android.widget.Toast;import androidx.activity.EdgeToEdge;
import androidx.annotation.Px;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {private PxScale pxScale;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pxScale = new PxScale();pxScale.checkbddata("zojdoifjaoidj");String hello = pxScale.sayHello();Toast.makeText(this, hello, Toast.LENGTH_SHORT).show();}
}

2.5 总结

  一般项目和NativeC++项目相比,想要使用JNI需要自己去创建cpp目录、cpp文件、CMakeLists.txt等,这些文件的组成语法都是大同小异的,唯一值得注意的就是需要自己在build.gradle中去声明项目JNI的相关信息,不然无法运行。

点击下载 一般项目使用JNI 的 Demo APP:https://github.com/xuhao120833/Server

三、C/C++调用Java方法

  前文举例子一直用的都是Java通过JNI去调用C/C++,那么反过来怎么弄呢???

从C/C++使用JNI调用Java方法分两种情况,一种是调用static静态方法,一种是调用普通方法,下面就分这两种情况分别说。

3.1 调用静态方法

相关文章:

Android JNI的理解与使用。

写在前面&#xff1a;Java相对于C/C来说是更高级的语言&#xff0c;隐藏了指针&#xff0c;可读性更高&#xff0c;更容易学习&#xff0c;但是无法直接操作硬件、运行速度较慢也是不可回避的硬伤。JNI就是Java官方定义的一套标准“接口”&#xff0c;用于Java和C/C之间互相调用…...

解决DeepSeek服务器繁忙的有效方法

全球42%的企业遭遇过AI工具服务器过载导致内容生产中断&#xff08;数据来源&#xff1a;Gartner 2025&#xff09;。当竞品在凌晨3点自动发布「智能家居安装指南」时&#xff0c;你的团队可能正因DeepSeek服务器繁忙错失「净水器保养教程」的流量黄金期⏳。147SEO智能调度系统…...

PyInstaller全平台打包深度解析:资源打包与路径兼容终极方案

一、典型问题场景分析 案例现象&#xff1a;PyQt5开发的GUI程序本地运行正常&#xff0c;但打包后出现以下问题&#xff1a; 程序图标丢失CSS样式表失效图片资源无法加载配置文件读取失败 问题本质&#xff1a;PyInstaller默认不会打包非代码资源文件&#xff0c;且打包后程…...

FreeSwitch的mod_spandsp模块

FreeSWITCH 的 mod_spandsp 模块是一个基于 Spandsp 库 的核心模块&#xff0c;主要用于实现 传真&#xff08;Fax&#xff09;、DTMF 信号处理 以及 语音编解码转换 等功能。它通过集成 SpandSP 的数字信号处理能力&#xff0c;使 FreeSWITCH 能够与传统通信系统&#xff08;如…...

【c++】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗?

【c】【Linux】【进程】线程终止/崩溃 会导致进程终止/崩溃 吗&#xff1f; 1.线程终止会导致进程终止吗&#xff1f; 在操作系统中&#xff0c;线程是进程的基本执行单元&#xff0c;一个进程可以包含一个或多个线程。 当一个子线程终止时&#xff0c;进程并不会因此自动终…...

Deepseek 怼CHATGPT实况

提示词&#xff1a; 用犀利的语言批评ChatGPT 深度思考&#xff08;R1) 嗯&#xff0c;用户让我用犀利的语言批评ChatGPT。首先&#xff0c;我需要理解他们的动机。可能他们遇到了ChatGPT的某些问题&#xff0c;比如回答不准确或者缺乏深度&#xff0c;所以想表达不满。也有…...

内核数据结构用法(2)list

list 在 Linux 内核中&#xff0c;链表操作是通过一组宏和函数来实现的&#xff0c;这些操作通常用来管理和遍历链表。以下是一些常用的链表函数和宏的具体用法。 1. 定义链表节点 首先&#xff0c;你需要定义一个包含 struct list_head 的结构体&#xff1a; #include <…...

量化自学 - 金融理论与python - Net Present Value 净现值

净现值&#xff08;Net Present Value&#xff0c;NPV&#xff09;是金融理论中用于评估投资项目价值的指标。其核心思想是将未来现金流按一定贴现率折算为当前价值&#xff0c;并减去初始投资成本。若NPV为正&#xff0c;表明项目预期收益高于成本&#xff0c;具有投资价值&am…...

Java Web开发实战与项目——用户认证与授权模块开发

Web应用中&#xff0c;用户认证与授权是至关重要的功能&#xff0c;确保只有合法用户才能访问受保护的资源。Spring Security作为一个强大的安全框架&#xff0c;支持多种认证与授权方式。在本章节中&#xff0c;我们将深入探讨三种常见的用户认证与授权方案&#xff1a;基于To…...

蓝桥杯篇---IAP15F2K61S2中断

文章目录 前言简介中断源1.外部中断2.定时器中断3.串口中断4.ADC中断5.PCA中断6.SPI中断7.PWM中断 中断优先级中断相关寄存器1.IE2.IP3.TCON4.SCON 中断使用步骤1.配置中断源2.使能中断3.设置优先级4.编写中断服务程序5.清除中断标志 示例代码&#xff1a;外部中断使用示例代码…...

django连接mysql数据库

1.下载mysqlclient第三方库 2.在settings.py里连接数据库&#xff08;提前建好&#xff09; DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: 学生信息,USER: root,PASSWORD: 999123457,HOST: localhost,POST: 3306,} } 3.在models.py里创建一个类&#xff0…...

Python爬虫TLS

TLS指纹校验原理和绕过 浏览器可以正常访问&#xff0c;但是用requests发送请求失败。 后端是如何监测得呢&#xff1f;为什么浏览器可以返回结果&#xff0c;而requests模块不行呢&#xff1f; https://cn.investing.com/equities/amazon-com-inc-historical-data 1.指纹校…...

Docker 部署 MySQL 8 详细图文教程

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …...

基于Python的Diango旅游数据分析推荐系统设计与实现+毕业论文(15000字)

基于Python的Diango旅游数据分析推荐系系统设计与实现毕业论文指导搭建视频&#xff0c;带爬虫 配套论文1w5字 可定制到某个省份&#xff0c;加40 基于用户的协同过滤算法 有后台管理 2w多数据集 可配套指导搭建视频&#xff0c;加20 旅游数据分析推荐系统采用了Python语…...

网络安全java练习平台 js网络安全

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 网上学习资料一大堆&#xff0c;但如果学到的知识不成体系&#xff0c;遇到问题时只是浅尝辄止&#xff0c;不再深入研究&#xff0c;那么很难做到真正的技术提升…...

在做题中学习(90):螺旋矩阵II

解法&#xff1a;模拟 思路&#xff1a;创建相同大小的一个二维数组&#xff08;矩阵&#xff09;&#xff0c;用变量标记原矩阵的行数和列数&#xff0c;每次遍历完一行或一列&#xff0c;相应行/列数--&#xff0c;进行对应位置的赋值即可。此题是正方形矩阵&#xff0c;因此…...

Educational Codeforces Round 174 (Rated for Div. 2)(ABCD)

A. Was there an Array? 翻译&#xff1a; 对于整数数组 ​&#xff0c;我们将其相等特征定义为数组 &#xff0c;其中&#xff0c;如果数组 a 的第 i 个元素等于其两个相邻元素&#xff0c;则 &#xff1b;如果数组 a 的第 i 个元素不等于其至少一个相邻元素&#xff0c;则 …...

qemu启动aarch64 linux+ buildroot + 应用程序

1、Linux内核网址 https://www.kernel.org/ 2、安装依赖 sudo apt update sudo apt install -y build-essential qemu qemu-system gcc make bc flex bison libssl-dev libncurses5-dev libelf-dev 3、拉取kernel代码和编译kernel git clone --depth 1 https://git.ker…...

Sponge VS Spring:新兴力量与行业标准的碰撞

框架特性对比 特性SpongeSpring编程语言Go (Golang)Java设计范式低代码, 代码生成, 模块化IoC (控制反转), DI (依赖注入), AOP (面向切面编程)性能高性能, 执行速度快, 并发性好成熟的性能, 需要 JVM 调优, 启动时间可能较长成熟度与稳定性较新, 快速发展中非常成熟, 行业标准…...

推荐几款较好的开源成熟框架

一. 若依&#xff1a; 1. 官方网站&#xff1a;https://doc.ruoyi.vip/ruoyi/ 2. 若依SpringBootVueElement 的后台管理系统&#xff1a;https://gitee.com/y_project/RuoYi-Vue 3. 若依SpringBootVueElement 的后台管理系统&#xff1a;https://gitee.com/y_project/RuoYi-Cl…...

【分布式】Hadoop完全分布式的搭建(零基础)

Hadoop完全分布式的搭建 环境准备&#xff1a; &#xff08;1&#xff09;VMware Workstation Pro17&#xff08;其他也可&#xff09; &#xff08;2&#xff09;Centos7 &#xff08;3&#xff09;FinalShell &#xff08;一&#xff09;模型机配置 0****&#xff09;安…...

JavaScript 异步编程:Promise 与 await 的关联与使用

在 JavaScript 中&#xff0c;异步编程是处理耗时操作&#xff08;如网络请求、文件读写等&#xff09;的核心机制。Promise 和 await 是两种常用的异步编程工具&#xff0c;它们密切相关&#xff0c;但又有各自的特点和适用场景。本文将深入探讨它们的关联、区别以及如何在实际…...

体验用ai做了个python小游戏

体验用ai做了个python小游戏 写在前面使用的工具2.增加功能1.要求增加视频作为背景。2.我让增加了一个欢迎页面。3.我发现中文显示有问题。4.我提出了背景修改意见&#xff0c;欢迎页面和结束页面背景是视频&#xff0c;游戏页面背景是静态图片。5.提出增加更多游戏元素。 总结…...

golang常用库之-swaggo/swag根据注释生成接口文档

文章目录 golang常用库之-swaggo/swag库根据注释生成接口文档什么是swaggo/swag golang常用库之-swaggo/swag库根据注释生成接口文档 什么是swaggo/swag github&#xff1a;https://github.com/swaggo/swag 参考文档&#xff1a;https://golang.halfiisland.com/community/pk…...

【可实战】Linux 常用统计命令:排序sort、去重uniq、统计wc

在 Linux 系统中&#xff0c;有一些常用的命令可以用来收集和统计数据。 一、常用统计命令的使用场景 日志分析和监控&#xff1a;通过使用 Linux 统计命令&#xff0c;可以实时监控和分析系统日志文件&#xff0c;了解系统的运行状况和性能指标。例如&#xff0c;使用 tail 命…...

【设计模式】【创建型模式】建造者模式(Builder)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…...

UE5.3 C++ 通过Spline样条实现三维连线,自己UV贴图。

一.制作了基于USplineComponent的画线插件&#xff0c;就是我们常说的样条线。 直接看怎么用&#xff0c;关于插件实现细节&#xff0c;后续会更新&#xff0c;看思路就行。通过ID,管理每一条线。移除删掉上一帧的线条Mesh。第一个点&#xff0c;是本身直接放过去。第二个点是…...

每日学习Java之一万个为什么

9.Class <?> class1 Myclass.class 为什么要有通配符&#xff1f;传给谁用的&#xff1f; 首先&#xff0c;这里的class特指某个对象在JVM中的元数据集合。 有普通、接口、数组、基本类型、 void 类型、局部类、匿名类、枚举、注解 1.类型安全&#xff1a;通配符允许…...

4、IP查找工具-Angry IP Scanner

在前序文章中&#xff0c;提到了多种IP查找方法&#xff0c;可能回存在不同场景需要使用不同的查找命令&#xff0c;有些不容易记忆&#xff0c;本文将介绍一个比较优秀的IP查找工具&#xff0c;可以应用在连接树莓派或查找IP的其他场景中。供大家参考。 Angry IP Scanner下载…...

华为昇腾920b服务器部署DeepSeek翻车现场

最近到祸一台HUAWEI Kunpeng 920 5250&#xff0c;先看看配置。之前是部署的讯飞大模型&#xff0c;发现资源利用率太低了。把5台减少到3台&#xff0c;就出了他 硬件配置信息 基本硬件信息 按照惯例先来看看配置。一共3块盘&#xff0c;500G的系统盘&#xff0c; 2块3T固态…...

一周学会Flask3 Python Web开发-http响应状态码

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在Flask程序中&#xff0c;客户端发出的请求触发相应的视图函数&#xff0c;获取返回值会作为响应的主体&#xff0c;最后生成…...

Javascript网页设计实例:通过JS实现上传Markdown转化为脑图并下载脑图

功能预览 深度与密度测试 对于测试部分&#xff0c;分别对深度和密度进行了测试&#xff1a; 注意&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;只实现了识别Markdown中的#代表的层级&#xff0c;所以不能使用其余标识符&#xff0…...

【Spring生命周期】Bean元信息配置阶段

引言 本系列将详细讲解Spring生命周期的13个阶段&#xff0c;从源码角度帮助我们更好的理解Spring框架和bean生命周期全流程 Bean信息定义4种方式 API的方式Xml文件方式properties文件的方式注解的方式 在 Spring 框架中&#xff0c;Bean 元信息配置阶段是整个 Bean 生命周…...

【iOS】SwiftUI状态管理

State ObservedObject StateObject 的使用 import SwiftUIclass CountModel: ObservableObject {Published var count: Int 0 // 通过 Published 标记的变量会触发视图更新init() {print("TimerModel initialized at \(count)")} }struct ContentView: View {State…...

ubuntu上如何查看coredump文件默认保存在哪个路径?

在 Ubuntu 系统中&#xff0c;可以通过以下几种方式来查看 coredump 文件默认保存的路径&#xff1a; 1. 查看core_pattern配置 core_pattern是一个内核参数&#xff0c;它决定了 coredump 文件的保存位置和命名规则。可以通过以下命令查看其当前值&#xff1a; cat /proc/s…...

技术总结汇总

目录 数据库 数据库系统原理 MySQL Redis Java Java 基础 Java 容器 Java 并发 Java 虚拟机 Java I/O 系统设计 系统设计基础 微服务 分布式 集群和负载均衡 灾备和故障转移 限流 降级和熔断 缓存 消息队列 设计模式 DDD领域驱动设计 开发框架和中间件…...

Java-如何将其他地方拉取的jar包导入本地maven环境

背景 公司的一个老旧二开项目&#xff0c;原项目维护方不合作了&#xff0c;提供的项目源码提供给到公司。项目中用到了一些原维护方内部的jar包&#xff0c;导致二开时依赖的这些部分全部报错。虽然在项目中直接导入此jar包可以解决报红报错问题&#xff0c;但是在使用maven打…...

Unity 聊天气泡根据文本内容适配

第一步 拼接UI 1、对气泡图进行九宫图切割 2、设置底图pivot位置和对齐方式 pivot位置&#xff1a;&#xff08;0&#xff0c;1&#xff09; 对齐方式&#xff1a;左上对齐 3、设置文本pivot位置和对齐方式&#xff0c;并挂上布局组件 pivot设置和对齐方式和底图一样&#…...

【组态PLC】基于博图V16和组态王六层双部电梯组态设计【含PLC组态源码 M008期】

控制要求 1&#xff09;两台电梯同时运行时&#xff0c;共同享用一套外呼按钮。 2&#xff09;当两台电梯同时去响应外呼信号时&#xff0c;两台电梯自动定向启动前往相应的楼层&#xff0c;当某一台电梯先行到达指定层楼时&#xff0c;另外一台电梯必须就近停靠平层&#xf…...

Python--数据类型(中)

1. 列表&#xff08;list&#xff09; 1.1 定义与特性 定义&#xff1a;有序、可变的容器&#xff0c;支持多种数据类型混合存储。 user_list ["奥力给", 98, True] empty_list [] # 空列表可变性&#xff1a;列表内部元素可修改&#xff0c;区别于字符串和元组。…...

学习总结2.19

首先就是对dfs和bfs的熟悉&#xff0c;dfs是一种递归函数&#xff0c;通过不断深搜来达到目的&#xff0c;通常用于寻找多少未知量&#xff0c;相较于bfs&#xff0c;编译难度更低一点&#xff1b;bfs多用于寻找最短路径之类&#xff0c;相较于dfs代码多了一部分队列的代码&…...

[Vivado报错] [Runs 36-527] DCP does not exist

一、错误原因解析 此错误表明Vivado在指定路径未找到.dcp&#xff08;Design Checkpoint&#xff09;文件&#xff0c;通常由以下原因导致&#xff1a; 路径过长或特殊字符&#xff1a;Windows系统路径长度限制&#xff08;260字符&#xff09;可能导致文件生成失败&#xff…...

深度学习的集装箱箱号OCR识别技术,识别率99.9%

集装箱箱号OCR识别技术是一项结合计算机视觉和规则校验的复杂任务&#xff0c;以下是其关键要点及实现思路的总结&#xff1a; 1、集装箱号结构&#xff1a;11位字符&#xff0c;格式为公司代码(3字母)和序列号(6数字)以及校验码(1数字)和尺寸/类型代码(可选)&#xff0c;例如…...

基于java新闻管理系统,推荐一款开源cms内容管理系统ruoyi-fast-cms

一、项目概述 1.1 项目背景 在信息高速流通的当下&#xff0c;新闻媒体行业每天都要处理和传播海量信息。传统的新闻管理模式依赖人工操作&#xff0c;在新闻采集、编辑、发布以及后续管理等环节中&#xff0c;不仅效率低下&#xff0c;而且容易出现人为失误。同时&#xff0…...

网络安全要学python 、爬虫吗

网络安全其实并不复杂&#xff0c;只是比普通开发岗位要学习的内容多一点。无论是有过编程基础还是零基础的都可以学习的。网络安全目前可就业的岗位从技术上可分为两部分&#xff1a;web安全和二进制逆向安全。web安全是网络安全的入门方向&#xff0c;内容简单&#xff0c;就…...

ChatGPT行业热门应用提示词案例-AI绘画类

AI 绘画指令是一段用于指导 AI 绘画工具&#xff08;如 DALLE、Midjourney 等&#xff09;生成特定图像的文本描述。它通常包含场景、主体、风格、色彩、氛围等关键信息&#xff0c;帮助 AI 理解创作者的意图&#xff0c;从而生成符合要求的绘画作品。 ChatGPT 拥有海量的知识…...

网络安全钓鱼邮件测试 网络安全 钓鱼

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 如今&#xff0c;网络安全是一个备受关注的话题&#xff0c;“网络钓鱼”这个词也被广泛使用。 即使您对病毒、恶意软件或如何在线保护自己一无所知&#xff0c;您…...

写一个python组件

写一个python组件 核心功能代码命令行接口打包配置安装与测试注意 写一个python组件&#xff0c;具体的&#xff1a;项目结构设计&#xff1a;定义你的项目的目录结构。编写核心功能代码&#xff1a;实现你想要的功能。创建命令行接口(CLI)&#xff1a;使用argparse或click库来…...

deepseek-v3在阿里云和腾讯云的使用中的差异

随着deepseek在各大云商上线&#xff0c;试用了下阿里云和腾讯云的deepseek服务&#xff0c;在回答经典数学问题9.9和9.11谁大时&#xff0c;发现还是有差异的。将相关的问题记录如下。 1、问题表现 笔者使用的openai的官方sdk go-openai。 因本文中测验主要使用阿里云和腾讯…...

DevOps自动化部署详解:从理念到实践

在软件开发日益快速迭代的今天&#xff0c;如何以高效、稳定且可重复的方式将代码变更从开发环境自动部署到生产环境成为企业竞争的重要因素。DevOps 正是在这一背景下应运而生&#xff0c;它打破开发、测试、运维之间的壁垒&#xff0c;通过自动化工具和流程&#xff0c;实现持…...