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

通过 JNI 实现 Java 与 Rust 的 Channel 消息传递

做纯粹的自己。“你要搞清楚自己人生的剧本——不是父母的续集,不是子女的前传,更不是朋友的外篇。对待生命你不妨再大胆一点,因为你好歹要失去它。如果这世上真有奇迹,那只是努力的另一个名字”。

一、crossbeam_channel

参考 crossbeam_channel - Rust

crossbeam_channel 是一个多生产者多消费者通道,用于消息传递,它是std::sync::mpsc的替代品,具有更多的功能和更好的性能。

二、Channel 类型

通道可以使用两个函数创建:

  1. bounded 函数创建一个容量有限的信道,即一个信道一次可以容纳的消息数量是有限制的。
  2. unbounded 函数创建一个容量无界的信道,即它一次可以容纳任意数量的消息。

这两个函数都返回一个发送方 Sender 和一个接收方 Receiver,它们代表通道的相反两端。

创建一个有界 Channel:

use crossbeam_channel::bounded;// Create a channel that can hold at most 5 messages at a time.
let (s, r) = bounded(5);// Can send only 5 messages without blocking.
for i in 0..5 {s.send(i).unwrap();
}// Another call to `send` would block because the channel is full.
// s.send(5).unwrap();

创建一个无界 Channel:

use crossbeam_channel::unbounded;// Create an unbounded channel.
let (s, r) = unbounded();// Can send any number of messages into the channel without blocking.
for i in 0..1000 {s.send(i).unwrap();
}

三、通过 JNI 使用 Channel

Java 端可以通过 JNI 调用 getSender 获取发送端指针,调用 sendMessage 发送消息到 Rust 中的处理线程,由 Rust 负责处理核心逻辑。

1、新建一个 Rust 库项目

cargo new rust_jni_channel_test --lib

添加依赖包, 

# Cargo.toml[dependencies]
jni = "0.21.1"
lazy_static = "1.5.0"
crossbeam-channel = "0.5.13"
#log = "0.4"
#env_logger = "0.11"[lib]
crate_type = ["cdylib"]

实现 JNI 模块函数, 

// lib.rs#[macro_use]
extern crate lazy_static;use jni::objects::{JClass, JObject};
use jni::sys::{jlong, jobject};
use jni::JNIEnv;
use crossbeam_channel::{unbounded, Sender, Receiver};
use std::thread;lazy_static! {static ref SENDER: Sender<String> = {let (sender, receiver) = unbounded();// Spawn a thread to handle the receiverthread::spawn(move || {for message in receiver.iter() {println!("Received message: {}", message);}});sender};
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_MyResultHandler_getSender(_env: JNIEnv,_class: JClass,
) -> jlong {let sender_ptr = Box::into_raw(Box::new(SENDER.clone())) as jlong;sender_ptr
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_MyResultHandler_sendMessage(mut env: JNIEnv,_class: JClass,sender_ptr: jlong,message: JObject,
) {let sender = unsafe { &*(sender_ptr as *mut Sender<String>) };let message: String = env.get_string(&message.into()).expect("Couldn't get java string!").into();match sender.send(message) {Ok(_) => println!("Message sent successfully"),Err(e) => eprintln!("Failed to send message: {:?}", e),}
}

以上代码主要做了三件事情: 

1、定义静态变量

  • 使用lazy_static!宏定义一个静态变量SENDER,它是一个Sender<String>类型的通道发送端。
  • 创建一个无界通道(unbounded channel),返回一个发送端和接收端。
  • 启动一个新线程,在该线程中不断从接收端读取消息并打印出来。
  • 返回发送端sender

2、实现JNI函数:获取发送端:Java_com_yushanma_MyResultHandler_getSender

  • 这个函数名遵循JNI命名规则,表示这是一个供Java调用的本地方法。
  • 函数参数包括JNI环境指针_env和Java类_class
  • 将静态变量SENDER克隆后转换为原始指针,再将其转换为jlong类型返回给Java。

 3、实现JNI函数:发送消息Java_com_yushanma_MyResultHandler_sendMessage

  • 这个函数同样遵循JNI命名规则。
  • 参数包括JNI环境指针env、Java类_class、发送端指针sender_ptr和Java字符串对象message
  • sender_ptr转换回Sender<String>类型的引用。
  • 从Java字符串对象中提取出Rust字符串。
  • 尝试通过发送端发送消息,如果成功则打印成功信息,否则打印错误信息。

2、新建一个 Maven 项目

package com.yushanma;import java.io.IOException;/*** @version: V1.0* @author: 余衫马* @description: 主函数* @data: 2024-11-22 19:24**/public class MyResultHandler {private static native long getSender();private static native void sendMessage(long senderPtr, String message);// 用于加载包含本地方法实现的本地库。static {System.loadLibrary("rust_jni_channel_test");}public static void main(String[] args) throws IOException {long senderPtr = getSender();new Thread(() -> {for (int i = 0; i < 100; i++) {sendMessage(senderPtr, String.format("Hello from Java! COUNT * %d", i + 1));}}).start();new Thread(() -> {for (int i = 100; i < 200; i++) {sendMessage(senderPtr, String.format("Hello from Java! COUNT * %d", i + 1));}}).start();System.in.read();}
}

 我们声明了两个本地方法getSendersendMessage,它们分别用于获取发送端指针和发送消息,对应 Rust 库中封装的两个 Native 方法。然后在 main 函数中,启动两个新线程,每个线程发送100条消息到Rust端,并且使用System.in.read()阻塞主线程,以防止程序过早退出。

3、添加外部 libs 与 VM 启动参数

-Djava.library.path=D:\JWorkSpace\ChannelDeomo\libs

 通过 VM 参数指定外部库路径,否则会直接使用默认路径,会报错找不到 dll 文件。

4、运行效果

四、封装

1、新建 Callback 类

package com.yushanma.callback;import java.time.LocalDateTime;/*** @version: V1.0* @author: 余衫马* @description: 回调类* @data: 2024-11-22 19:30**/
public class MyCallback {// 用于加载包含本地方法实现的本地库。static {System.loadLibrary("rust_jni_channel_test");}/*** Sender 指针*/private final long senderPtr;/*** 获取 Sender 指针** @return*/private static native long getSender();/*** 发送信息** @param senderPtr Sender 指针* @param message   信息内容*/private static native void sendMessage(long senderPtr, String message);/*** 默认构造方法*/public MyCallback() {senderPtr = getSender();}/*** 回调方法*/public void callback(String out) {sendMessage(senderPtr, String.format("%s callback data: %s, senderPtr %d", LocalDateTime.now(), out, senderPtr));}}
package com.yushanma;import com.yushanma.callback.MyCallback;import java.io.IOException;
import java.util.UUID;/*** @version: V1.0* @author: 余衫马* @description: 主函数* @data: 2024-11-22 19:24**/public class MyResultHandler {public static void main(String[] args) throws IOException {new Thread(() -> {MyCallback myCallback = new MyCallback();for (int i = 0; i < 10; i++) {myCallback.callback(UUID.randomUUID().toString());}}).start();new Thread(() -> {MyCallback myCallback = new MyCallback();for (int i = 0; i < 10; i++) {myCallback.callback(UUID.randomUUID().toString());}}).start();System.in.read();}
}

2、Rust 修改命名路径

#[macro_use]
extern crate lazy_static;use jni::objects::{JClass, JObject};
use jni::sys::{jlong, jobject};
use jni::JNIEnv;
use crossbeam_channel::{unbounded, Sender, Receiver};
use std::thread;lazy_static! {static ref SENDER: Sender<String> = {let (sender, receiver) = unbounded();// Spawn a thread to handle the receiverthread::spawn(move || {for message in receiver.iter() {println!("Received message: {}", message);}});sender};
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_callback_MyCallback_getSender(_env: JNIEnv,_class: JClass,
) -> jlong {let sender_ptr = Box::into_raw(Box::new(SENDER.clone())) as jlong;sender_ptr
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_callback_MyCallback_sendMessage(mut env: JNIEnv,_class: JClass,sender_ptr: jlong,message: JObject,
) {let sender = unsafe { &*(sender_ptr as *mut Sender<String>) };let message: String = env.get_string(&message.into()).expect("Couldn't get java string!").into();match sender.send(message) {Ok(_) => println!("Message sent successfully"),Err(e) => eprintln!("Failed to send message: {:?}", e),}
}

路径要保持一致,否则调用本地方法时会报错找不到函数。

3、运行效果

五、内存释放

在 Java 中,JVM(Java Virtual Machine)管理着内存的分配和释放。对于纯 Java 对象,JVM 的垃圾回收机制会自动处理对象的生命周期。然而,当涉及到与本地代码(如 Rust 或 C/C++)交互时,需要特别注意资源的管理。

在这个示例中,MyCallback 是一个通过 JNI(Java Native Interface)或类似技术与 Rust 代码交互的类。senderPtr 是一个指向本地(Rust)资源的指针。当 MyCallback 实例 lib 被垃圾回收时,JVM 并不会自动知道如何释放 senderPtr 所指向的本地资源。这意味着我们需要手动管理这些资源,以避免内存泄漏。

1、显式释放资源

在 MyCallback 类中提供一个方法,用于显式释放本地资源。

package com.yushanma.callback;import java.time.LocalDateTime;/*** @version: V1.0* @author: 余衫马* @description: 回调类* @data: 2024-11-22 19:30**/
public class MyCallback {// 用于加载包含本地方法实现的本地库。static {System.loadLibrary("rust_jni_channel_test");}/*** Sender 指针*/private long senderPtr;/*** 获取 Sender 指针** @return*/private static native long getSender();/*** 发送信息** @param senderPtr Sender 指针* @param message   信息内容*/private static native void sendMessage(long senderPtr, String message);/*** 释放资源* @param senderPtr Sender 指针*/private static native void releaseSender(long senderPtr);/*** 默认构造方法*/public MyCallback() {senderPtr = getSender();}/*** 回调方法*/public void callback(String out) {sendMessage(senderPtr, String.format("%s callback data: %s, senderPtr %d", LocalDateTime.now(), out, senderPtr));}/*** 释放资源*/public void release(){releaseSender(senderPtr);senderPtr = 0;}/*** 重载 Object 类的 finalize 方法* 不推荐依赖 finalize 方法,因为它的执行时间是不确定的,但作为最后的防线,可以在 finalize 方法中释放资源。* @throws Throwable*/@Overrideprotected void finalize() throws Throwable {try {if (senderPtr != 0) {releaseSender(senderPtr);}} finally {super.finalize();}}
}

2、使用 AutoCloseable 接口

package com.yushanma.callback;import java.time.LocalDateTime;/*** @version: V1.0* @author: 余衫马* @description: 回调类* @data: 2024-11-22 19:30**/
public class MyCallback implements AutoCloseable  {// 用于加载包含本地方法实现的本地库。static {System.loadLibrary("rust_jni_channel_test");}/*** Sender 指针*/private long senderPtr;/*** 获取 Sender 指针** @return*/private static native long getSender();/*** 发送信息** @param senderPtr Sender 指针* @param message   信息内容*/private static native void sendMessage(long senderPtr, String message);/*** 释放资源* @param senderPtr Sender 指针*/private static native void releaseSender(long senderPtr);/*** 默认构造方法*/public MyCallback() {senderPtr = getSender();}/*** 回调方法*/public void callback(String out) {sendMessage(senderPtr, String.format("%s callback data: %s, senderPtr %d", LocalDateTime.now(), out, senderPtr));}//    /**
//     * 释放资源
//     */
//    public void release(){
//        releaseSender(senderPtr);
//        senderPtr = 0;
//    }
//
//    /**
//     * 重载 Object 类的 finalize 方法
//     * 不推荐依赖 finalize 方法,因为它的执行时间是不确定的,但作为最后的防线,可以在 finalize 方法中释放资源。
//     * @throws Throwable
//     */
//    @Override
//    protected void finalize() throws Throwable {
//        try {
//            if (senderPtr != 0) {
//                releaseSender(senderPtr);
//            }
//        } finally {
//            super.finalize();
//        }
//    }/*** 释放资源*/@Overridepublic void close() {if (senderPtr != 0) {releaseSender(senderPtr);senderPtr = 0;}}}
try (MyCallback myCallback = new MyCallback()) {for (int i = 0; i < 10; i++) {myCallback.callback(UUID.randomUUID().toString());}
} // 自动调用 myCallback.close() 方法

3、Rust 释放内存逻辑

添加一个新的 JNI 函数来释放 Sender,并确保在释放时不会发生内存泄漏或其他问题。

#[macro_use]
extern crate lazy_static;use jni::objects::{JClass, JObject};
use jni::sys::{jlong, jobject};
use jni::JNIEnv;
use crossbeam_channel::{unbounded, Sender, Receiver};
use std::thread;lazy_static! {static ref SENDER: Sender<String> = {let (sender, receiver) = unbounded();// Spawn a thread to handle the receiverthread::spawn(move || {for message in receiver.iter() {println!("Received message: {}", message);}});sender};
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_callback_MyCallback_getSender(_env: JNIEnv,_class: JClass,
) -> jlong {let sender_ptr = Box::into_raw(Box::new(SENDER.clone())) as jlong;sender_ptr
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_callback_MyCallback_sendMessage(mut env: JNIEnv,_class: JClass,sender_ptr: jlong,message: JObject,
) {let sender = unsafe { &*(sender_ptr as *mut Sender<String>) };let message: String = env.get_string(&message.into()).expect("Couldn't get java string!").into();match sender.send(message) {Ok(_) => println!("Message sent successfully"),Err(e) => eprintln!("Failed to send message: {:?}", e),}
}#[no_mangle]
pub extern "system" fn Java_com_yushanma_callback_MyCallback_releaseSender(_env: JNIEnv,_class: JClass,sender_ptr: jlong,
) {if sender_ptr != 0 {unsafe {// Convert the raw pointer back to a Box and drop itlet _ = Box::from_raw(sender_ptr as *mut Sender<String>);}println!("Sender released");}
}

释放内存的关键在这里:

let _ = Box::from_raw(sender_ptr as *mut Sender<String>);

这行代码的作用是将一个原始指针(raw pointer)转换为一个 Box,从而恢复对堆上分配的内存的所有权。在 Rust 中,Box 是一个智能指针类型,用于管理堆上的内存。具体来说,这行代码执行了以下操作:

  1. 类型转换sender_ptr as *mut Sender<String> 将 sender_ptr 转换为一个可变的原始指针,指向 Sender<String> 类型的数据。
  2. 从原始指针创建 BoxBox::from_raw 接受一个原始指针,并返回一个 Box,从而接管该指针所指向的内存的所有权。

完整的解释如下:

  • sender_ptr 是一个原始指针,通常是通过某种方式获得的,例如通过 Box::into_raw 方法将一个 Box 转换为原始指针。
  • as *mut Sender<String> 是一个类型转换,将 sender_ptr 转换为一个指向 Sender<String> 的可变原始指针。
  • Box::from_raw(sender_ptr as *mut Sender<String>) 使用这个原始指针创建一个 Box<Sender<String>>,这样 Rust 的所有权系统就可以正确地管理这块内存。

需要注意的是,使用 Box::from_raw 时要确保:

  • 原始指针确实指向有效的堆内存。
  • 该内存之前是通过 Box 分配的。
  • 在调用 Box::from_raw 后,不再使用原始指针,因为 Box 会负责释放这块内存。

4、运行效果

相关文章:

通过 JNI 实现 Java 与 Rust 的 Channel 消息传递

做纯粹的自己。“你要搞清楚自己人生的剧本——不是父母的续集&#xff0c;不是子女的前传&#xff0c;更不是朋友的外篇。对待生命你不妨再大胆一点&#xff0c;因为你好歹要失去它。如果这世上真有奇迹&#xff0c;那只是努力的另一个名字”。 一、crossbeam_channel 参考 cr…...

一起学习Fortran:如何安装Fortran

Fortran&#xff08;全称Formula Translation&#xff0c;意为“公式翻译”&#xff09;是一种通用编译命令式编程语言&#xff0c;适用于数值计算和科学计算。Fortran语言最初是由IBM在20世纪50年代为科学和工程应用程序而开发的&#xff0c;第一个Fortran版本——FORTRAN I在…...

社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略

摘要&#xff1a;随着实体商业与社交网络深度融合&#xff0c;社交新零售蓬勃兴起&#xff0c;“21 链动模式 S2B2C 商城小程序”作为其中创新典范&#xff0c;融合独特激励机制与数字化运营优势&#xff0c;重塑零售生态。本文剖析该模式架构、运作逻辑&#xff0c;探讨其在私…...

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代&#xff0c;程序开…...

贝叶斯统计的核心思想与基础知识:中英双语

中文版 贝叶斯统计的核心思想与基础知识 贝叶斯统计是以贝叶斯定理为核心&#xff0c;通过将先验知识和观测数据相结合&#xff0c;更新对参数或模型的认知的一种统计方法。它不仅强调概率的频率解释&#xff08;频率统计学中概率描述事件的长期发生频率&#xff09;&#xf…...

Verilog使用liberty文件中cell单元的demo

Liberty&#xff08;.lib&#xff09;文件是用来描述标准单元库中逻辑单元&#xff08;如门电路、触发器等&#xff09;的时序和功耗特性的&#xff0c;不是用来直接定义Verilog中的元件。在Verilog设计中&#xff0c;我们通常通过实例化模块&#xff08;module&#xff09;来创…...

openssl生成ca证书

常见CA文件夹 1、生成CA钥匙 openssl genrsa -out ./private/cakey.pem 2、生成CA自签名 openssl req -new -x509 -key ./private/cakey.pem -out ./cacert.crt -days 3650 3、生成http服务器私钥 openssl genrsa -out ./data/frontt.project.com.key 2048 4、CA给http服务器…...

OGRE 3D----2. QGRE + QQuickView

将 OGRE(面向对象图形渲染引擎)集成到使用 QQuickView 的 Qt Quick 应用程序中,可以在现代灵活的 UI 框架中提供强大的 3D 渲染功能。本文将指导您如何在 QQuickView 环境中设置 OGRE。 前提条件 在开始之前,请确保您已安装以下内容: Qt(版本 5.15 )OGRE(版本14.2.5)…...

【Java 学习】面向程序的三大特性:封装、继承、多态

引言 1. 封装1.1 什么是封装呢&#xff1f;1.2 访问限定符1.3 使用封装 2. 继承2.1 为什么要有继承&#xff1f;2.2 继承的概念2.3 继承的语法2.4 访问父类成员2.4.1 子类中访问父类成员的变量2.4.2 访问父类的成员方法 2.5 super关键字2.6 子类的构造方法 3. 多态3.1 多态的概…...

Online Judge——【前端项目初始化】Vue-CLI初始化项目、组件库引入

目录 一、创建项目二、前端工程化配置三、引入组件 一、创建项目 输入命令&#xff1a;vue create oj-frontend来到如下界面&#xff1a; 选择Manually select features 选择如下图的组件&#xff1a;注意空格是选择&#xff0c;之后回车即可。 选择3.x版本 继续选择&#xff…...

ASP.NET Web(.Net Framework)POST无法正常接收数据

ASP.NET Web&#xff08;.Net Framework&#xff09;POST无法正常接收数据 介绍站点Post和Get如何打断点测试测试代码如下服务器站点Post方法修改原因总结 总结 介绍 这一篇文章主要是讲一下之前搭建的HTTP站点POST无法正常接收数据&#xff0c;如果还不知道怎么搭建HTTP站点的…...

vue安装cypress及其部分用法

安装Cypress 在vue中安装Cypress 1. 安装 Cypress 首先&#xff0c;确保你已经安装了 Cypress。在你的 Vue 项目根目录下运行以下命令&#xff1a; npm install cypress --save-dev2. 打开 Cypress 安装完 Cypress 后&#xff0c;可以通过以下命令打开 Cypress 测试界面&a…...

Web Worker 入门:让前端应用多线程化

引出&#xff1a; 作为前端切图仔&#xff0c;在之前的工作中一直都是写后台&#xff0c;没机会用到web Worker&#xff0c;传统的性能优化web Worker用到的场景也很少&#xff0c;毕竟大量的数据计算一般直接给后端去做就行&#xff0c;轮不到前端来考虑&#xff08;没遇到类似…...

Vue+Elementui el-tree树只能选择子节点并且支持检索

效果&#xff1a; 只能选择子节点 添加配置添加检索代码 源码&#xff1a; <template><div><el-button size"small" type"primary" clearable :disabled"disabled" click"showSign">危险点评估</el-button>…...

MySQL各种问题的原因及解决方案梳理

背景&#xff1a;由于最近一直在做生产环境和测试环境的切换&#xff0c;遇到了各种各样的MySQL问题&#xff0c;为了后面的开发顺利&#xff0c;梳理一下MySQL的报错及解决方案 问题1、MySQL的链接数超过了本身MySQL内部设置的链接限制 报错信息&#xff1a; // An highlig…...

LeetCode—74. 搜索二维矩阵(中等)

仅供个人学习使用 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true…...

【Redis】Redis介绍

目录 1.Redis是什么? 2. Redis特性 2.1 速度快 2.2 基于键值对的数据结构服务器 2.3 丰富的功能 2.4 简单稳定 2.5 客户端语言多 2.6 持久化 2.7 主从复制 2.8 高可用和分布式 3. Redis使用场景 3.1 缓存(Cache) 3.2 排行榜系统 3.3 计数器应用 3.4 社交网络 …...

Python 3 教程第23篇(模块)

Python3 模块 在前面的几个章节中我们基本上是用 python 解释器来编程&#xff0c;如果你从 Python 解释器退出再进入&#xff0c;那么你定义的所有的方法和变量就都消失了。 为此 Python 提供了一个办法&#xff0c;把这些定义存放在文件中&#xff0c;为一些脚本或者交互式…...

课题组自主发展了哪些CMAQ模式预报相关的改进技术?

空气污染问题日益受到各级政府以及社会公众的高度重视&#xff0c;从实时的数据监测公布到空气质量数值预报及预报产品的发布&#xff0c;我国在空气质量监测和预报方面取得了一定进展。随着计算机技术的高速发展、空气污染监测手段的提高和人们对大气物理化学过程认识的深入&a…...

七牛云AIGC内容安全方案助力企业合规创新

随着人工智能生成内容(AIGC)技术的飞速发展,内容审核的难度也随之急剧上升。在传统审核场景中,涉及色情、政治、恐怖主义等内容的标准相对清晰明确,但在AIGC的应用场景中,这些界限变得模糊且难以界定。用户可能通过交互性引导AI生成违规内容,为审核工作带来了前所未有的不可预测…...

Vue.js 中的事件处理

在 Vue.js 中&#xff0c;事件处理是用户与应用交互的重要方式。Vue.js 允许开发者以一种声明式的方式来绑定事件监听器&#xff0c;这使得代码更加简洁和易于维护。本文将介绍 Vue.js 中的事件处理&#xff0c;包括常用的事件类型和如何使用它们。 Vue.js 事件基础 在 Vue.j…...

Windows用pm2部署node.js项目

Windows上pm2启动命令不生效 按照常规启动命令应该如下&#xff0c;但是发现不生效 pm2 start npm --name "project-name" -- start具体如下&#xff0c;可以看到状态都是stopped $ pm2 start npm --name "chatgpt-next-web" -- start [PM2] Starting …...

算法【Java】—— 动态规划之路径问题

前言 本文章终点解析第一道题目【不同路径】和最后一道题目【地下城游戏】的动态规划思路&#xff0c;中间几道题目会很快过完&#xff0c;大家如果不熟悉动态规划的思路可以重点看一下这两道题目的解析。 不同路径 https://leetcode.cn/problems/unique-paths 解析&#xf…...

DreamFace4.9.0 |AI照片动画师,让照片说话和跳舞

DreamFace是一款有趣的照片动画应用程序&#xff0c;通过AI技术让您的照片唱歌、跳舞甚至说话。只需上传照片并选择歌曲&#xff0c;即可生成动态效果。此外&#xff0c;它还支持图片增强、降噪和高清处理&#xff0c;创建人工智能驱动的头像。无论是让宠物说话还是让朋友唱情歌…...

vue-baidu-map基本使用

vue-baidu-map 是一个基于 Vue.js 的百度地图组件库&#xff0c;它封装了百度地图的 JavaScript API&#xff0c;使得在 Vue 项目中使用百度地图功能更加便捷。下面是如何在 Vue 项目中安装和使用 vue-baidu-map 的步骤&#xff1a; 安装 首先确保你的项目已经集成了 Vue 和 …...

新电脑验机-允许上网,同时禁止windows系统联网自动激活

效果&#xff1a; 重要提示&#xff1a;我虽然得到上图效果&#xff0c;但也不确定是否有坑&#xff0c;不保证商家是否认可。 笔记本电脑七天无理由退货的前提条件是“windows和office未激活”。如何 oobe\bypassnor 绕过开机联网并创建本地账号的方法我就不写了&#xff0c;搜…...

Android 是否支持AB分区

Android 是否支持AB分区 C:\Users\Administrator>adb shell bengal:/ $ su bengal:/ # getprop |grep treble [ro.treble.enabled]: [true] bengal:/ #返回不为空而且为true&#xff0c;那就是支持pt(project treble)分区 进入fastboot模式 adb reboot bootloader查看当前…...

Qt6.8安卓Android开发环境配置

时隔多年&#xff0c;重拾QtCreator下Android开发。发现Qt6下安卓开发环境配置变简单不少&#xff01;只需三步即可在QtCreator下进行Android开发&#xff1a; 一、使用Qt Mantenance Tool进行Android模块的安装&#xff1a; 如果感觉安装网速较慢&#xff0c;可以查看本人另外…...

JavaSE——类与对象(4)

一、静态变量 1.1为什么要有静态变量 现在有一群小朋友在做游戏&#xff0c;不是有新的小朋友加入&#xff0c;请问如何知道现在共有多少人在完&#xff1f;看这段代码&#xff1a; public class first {public static void main(String[] args) {int count 0;child child1 …...

网络编程中的字节序函数htonl()、htons()、ntohl()和ntohs()

目录 1&#xff0c;网络字节序和主机字节序 2. 函数的具体作用 2.1,htonl&#xff08;Host to Network Long&#xff09; 2.2,htons&#xff08;Host to Network Short) 2.3,ntohl&#xff08;Network to Host Long&#xff09; 2.4,ntohs&#xff08;Network to Host Sho…...

如何在HarmonyOS NEXT中处理页面间的数据传递?

大家好&#xff0c;前两天的Mate70的发布&#xff0c;让人热血沸腾啊&#xff0c;不想错过&#xff0c;自学的小伙伴一起啊&#xff0c;今天分享的学习笔记是关于页面间数据伟递的问题&#xff0c;在HarmonyOS NEXT 5.0 中&#xff0c;页面间的数据传递可以有很多种方式&#x…...

【Code First】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 &#x1f…...

Day28 贪心算法 part02

122.买卖股票的最佳时机II 本题解法很巧妙,本题大家可以先自己思考一下然后再看题解,会有惊喜! class Solution {public int maxProfit(int[] prices) {//分析每一天的情况。只要保证今天买,明天卖可以不亏钱,那就是最大的利润。把每一天可以赚钱的机会都不放过,先把能挣…...

JVM_栈详解一

1、栈的存储单位 **栈中存储什么&#xff1f;**&#xff0c; 每个线程都有自己的栈&#xff0c;栈中的数据都是以栈帧&#xff08;Stack Frame&#xff09;的格式存在。在这个线程上正在执行的每个方法都各自对应一个栈帧&#xff08;Stack Frame&#xff09;。 栈帧是一个内存…...

深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现

往期内容 本专栏往期内容&#xff1a;Uart子系统 UART串口硬件介绍深入理解TTY体系&#xff1a;设备节点与驱动程序框架详解Linux串口应用编程&#xff1a;从UART到GPS模块及字符设备驱动 解UART 子系统&#xff1a;Linux Kernel 4.9.88 中的核心结构体与设计详解IMX 平台UART驱…...

集成量子光子学(IQP)

IQP 正在成为量子计算的可行替代方案量子源、波导和调制器等领域的研究使这成为可能与 CMOS 技术的兼容意味着工业可扩展性将更加容易 量子光子学的基本组成部分 IQP 系统的基本组成部分包括&#xff1a; 来源&#xff08;例如腔体中的 QD&#xff09; 波导定向耦合器&#…...

【代码随想录|贪心算法02】

122.买股票的最佳时机 题目链接https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii 好巧妙的一道题啊&#xff0c;做之前完全不会想到这种解法。 局部最优&#xff1a;收集每天正利润 全局最优&#xff1a;求得最大利润 这道题只让你返回最大的利润和&…...

CentOS7 使用xtrabackup备份及恢复

安装备份工具 1.安装Percona yum存储库 sudo yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm安装过程中需要按y继续安装 2.启用Percona Server 5.7存储库 sudo percona-release setup ps573、安装percona-xtrabackup-24 sudo yum -y instal…...

【网络安全设备系列】12、态势感知

0x00 定义&#xff1a; 态势感知&#xff08;Situation Awareness&#xff0c;SA&#xff09;能够检测出超过20大类的云上安全风险&#xff0c;包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术&#xff0c;态势感…...

VM Virutal Box的Ubuntu虚拟机与windows宿主机之间设置共享文件夹(自动挂载,永久有效)

本文参考如下链接 How to access a shared folder in VirtualBox? - Ask Ubuntu &#xff08;1&#xff09;安装增强功能&#xff08;Guest Additions&#xff09; 首先&#xff0c;在网上下载VBoxGuestAdditions光盘映像文件 下载地址&#xff1a;Index of http://…...

【docker集群应用】Docker--harbor私有仓库部署与管理

文章目录 Harbor特性Harbor构成Harbor部署与管理Harbor 部署实例环境准备1. 部署 Docker-Compose 服务2. 部署 Harbor 服务(1) 下载并解压 Harbor 安装程序(2) 修改 Harbor 配置文件 3. 启动 Harbor4. 查看 Harbor 启动镜像5. 创建一个新项目6. 在其他客户端上传镜像 维护管理 …...

【优选算法】位运算

目录 常见位运算总结1、基础位运算2、给一个数n&#xff0c;确定它的二进制位的第x位上是0还是13、将一个数n的二进制位的第x位改成14、将一个数n的二进制位的第x位改成05、位图的思想6、提取一个数n的二进制位中最右侧的17、将一个数n的二进制位中最右侧的1变为08、位运算的优…...

2.mybatis整体配置

文章目录 mybatis-config.xml介绍SqlSessionFactoryBuilderXMLConfigBuilderpropertiessetting类型别名&#xff08;typeAliases&#xff09;扫描插件(plugins)解析objectFactory(对象工厂)解析objectWrapperFactory解析reflectorFactorysettingsElement()方法环境配置&#xf…...

js中判断数组和判断对象的方法

判断数组 Array.isArray() 方法 这是最推荐的方法&#xff0c;简单明了。它可以检测数组的情况&#xff0c;并且不会误报其他类型。 const arr [1, 2, 3]; console.log(Array.isArray(arr)); // trueconst notArray { key: value }; console.log(Array.isArray(notArray))…...

【godot】如何立刻(实时)进行碰撞检测?

因为最近在做帧同步方面的内容&#xff0c;所以发现了这个问题。 方案1&#xff1a;用Area2d进行碰撞检测&#xff0c;绑定body_entered信号。 缺陷&#xff1a; Area2d的碰撞检测只会每个物理迭代中只会执行一次&#xff0c;即在physics_process()结束后执行一次。 场景&a…...

讨论JAVA、JVM与Spring

Q1: 作为一个JAVA开发人员&#xff0c;对于jvm肯定不陌生&#xff0c;但很多人对它不陌生也仅止于概念上&#xff0c;而且对概念也是模糊不清的&#xff0c;但jvm实际是java程序运行在其中的实际存在的环境&#xff0c;对它的理解应该要是具象化的。 我们还是从一项技术产生的…...

基于SpringBoot实现的民宿管理系统(代码+论文)

&#x1f389;博主介绍&#xff1a;Java领域优质创作者&#xff0c;阿里云博客专家&#xff0c;计算机毕设实战导师。专注Java项目实战、毕设定制/协助 &#x1f4e2;主要服务内容&#xff1a;选题定题、开题报告、任务书、程序开发、项目定制、论文辅导 &#x1f496;精彩专栏…...

vue2 - 22.vant 组件库

vant 组件库 vant2下载&#xff1a; npm i vantlatest-v2 --legacy-peer-deps 目标&#xff1a;认识第三方 Vue组件库 vant-ui 组件库&#xff1a;第三方 封装 好了很多很多的 组件&#xff0c;整合到一起就是一个组件库。 https://vant-contrib.gitee.io/vant/v2/#/zh-CN…...

Git简单介绍

一、 Git介绍与安装 1.1 Git简介 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 1.2集中式(SVN&#xff09; VS 分布式(git) 集中式版本控制系统&#xff0c;版本库是集中存放在中央服务器的&#xff0c;工作时要先从中央…...

【ArcGIS Pro实操第11期】经纬度数据转化成平面坐标数据

经纬度数据转化成平面坐标数据 数据准备ArcGIS操作步骤-投影转换为 Sinusoidal1 投影2 计算几何Python 示例 另&#xff1a;Sinusoidal (World) 和 Sinusoidal (Sphere) 的主要区别参考 数据准备 数据投影&#xff1a; 目标投影&#xff1a;与MODIS数据相同&#xff08;Sinu…...