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

字符串的区别

C++ 和 Java 字符串的区别

最近 C++ 和 Java 在同步学习,都有个字符串类型,但二者不太一样,于是就做了些许研究。

在编程中,字符串作为数据类型广泛应用于不同的场景。虽然 C++ 和 Java 都允许我们处理字符串,但它们在字符串的表示、操作和管理方面有许多重要的不同之处。

1. 字符串表示

C++:
C++ 中的字符串可以使用 std::string 或 C 风格的字符串(字符数组(char*))表示。std::string 是 C++ 标准库提供的一个封装类,负责字符串的动态管理。而 C 风格字符串是以 null('\0')结尾的字符数组,更加底层,但需要手动管理内存。

#include <string>std::string str1 = "Hello, World!"; // 使用 std::string
const char* str2 = "Hello, World!";  // C 风格字符串

Java:
Java 中的字符串通过 String 类表示,所有字符串都是不可变的(immutable)。这种设计使得 Java 字符串在多线程环境中更安全,但也意味着频繁的字符串操作可能会导致额外的内存消耗和性能损失。

String str = "Hello, World!"; // Java 字符串

2. 内存管理

内存管理是编程语言设计中的关键特性,它直接影响程序的性能、效率和稳定性。在字符串处理方面,C++ 和 Java 采取了不同的策略来管理内存。下面将详细讨论这两种语言的内存管理方式。

C++ 的内存管理

在 C++ 中,内存管理由程序员负责,这为开发者提供了高灵活性,但也增加了出错的风险。

1. 动态内存分配

C++ 支持使用 newdelete 操作符进行动态内存分配和释放。对于 C 风格字符串(char*),开发者必须手动管理内存。

示例代码

#include <iostream>int main() {// 动态分配内存char* str = new char[20]; // 分配20个字符的空间// 使用 strcpy() 来复制字符串(需要包含 <cstring> 头文件)strcpy(str, "Hello, World!");std::cout << str << std::endl; // 输出: Hello, World!// 释放内存delete[] str; // 手动释放内存return 0;
}

2. std::string 的内存管理

使用 std::string 时,内存管理变得更加方便。std::string 自动处理内存分配和释放。它的内部机制会根据需要调整内存大小。

  • 追加和修改:当需要追加字符或修改字符串时,std::string 会自动调整其内部缓冲区,以便容纳新内容。
  • 尾部处理std::string 可以灵活地处理和释放内存,避免内存泄漏的风险。

示例代码

#include <iostream>
#include <string>int main() {std::string str = "Hello";str += ", World!"; // 自动管理内存std::cout << str << std::endl; // 输出: Hello, World!return 0; // str 的内存将在作用域结束时自动清理
}

3. 内存管理风险

尽管 std::string 提供了更好的内存管理,但容易由于以下原因导致内存泄漏或异常:

  • 未释放的动态内存:如果在使用 new 分配内存后忘记使用 delete 释放,程序将单元未释放的内存,会导致内存泄漏。
  • 野指针:在释放内存后继续使用该指针,会导致未定义的行为。
Java 的内存管理

Java 的内存管理采用了自动垃圾回收机制,减少了开发者在内存管理方面的负担。以下是 Java 内存管理的主要特点:

1. 垃圾回收机制

Java 的垃圾回收(Garbage Collection, GC)机制自动检测不再使用的对象,并清理其占用的内存。这使得开发者无需显式释放内存。

  • 根对象(Root Objects):垃圾回收器以根对象为起点,遍历应用程序中所有可达的对象,从而确定哪些对象是可以回收的。
  • 标记-清除算法:垃圾回收器使用标记-清除算法来标记活动对象并清理未被引用的对象。这样的机制能够防止内存泄漏。

示例代码

public class GarbageCollectionExample {public static void main(String[] args) {String str = new String("Hello, World!");// str 变量指向一个字符串对象// 在后续代码中,str 变量的作用域结束时,字符串对象将不再被使用str = null; // 明确表示不再使用字符串对象// 此时垃圾回收器会自动处理,回收未被引用的对象}
}

2. 内存分配区域

Java的内存管理在内存区域上可分为几部分:

  • 堆内存(Heap):用于动态分配对象,所有 Java 对象都在堆上创建。
  • 栈内存(Stack):用于存储局部变量和方法调用,生命周期由作用域决定。
  • 方法区(Method Area):存储类信息、常量、静态变量等。

3. 内存管理优势与局限

  • 优势

    • 易用性:开发者无需担心内存分配和释放,使得开发过程更为简洁。
    • 自动管理:自动 GC 减少了内存泄漏和野指针的问题。
  • 局限性

    • 性能开销:垃圾回收引入了性能开销,尤其在应用程序高负载时可能触发 GC,导致性能抖动。
    • 不可控性:开发者对内存释放过程没有控制权,这可能在某些情况下导致内存使用不够高效。
总结

C++ 和 Java 在内存管理方面采取了不同的策略,反映了各自的设计哲学与应用需求。

  • C++:通过手动管理内存,给予开发者更多的控制权,需要关注内存分配和释放,以避免内存泄漏和不必要的程序崩溃。std::string 提供了一部分自动管理的便利,但仍然需要开发者保持警惕。

  • Java:通过垃圾回收机制实现自动内存管理,使得开发者可以更专注于实际的业务逻辑,减少了内存管理方面的责任。但这也带来了一些性能上的开销,以及在某些情况下的不可控性。

3. 字符串操作

在处理字符串时,操作的便利性和灵活性对开发者的编码效率至关重要。C++ 和 Java 采用了不同的策略来实现字符串操作,下面我们将深入探讨 C++ 的运算符重载和 Java 的 StringBuilder 类。

C++ 的运算符重载

在 C++ 中,运算符重载是一个强大的特性,允许开发者重新定义基本运算符的行为。对于字符串操作来说,C++ 的 std::string 类已经重载了 ++= 运算符,这使得字符串的拼接变得非常直观。

示例代码
#include <iostream>
#include <string>int main() {std::string str1 = "Hello";std::string str2 = " World!";// 使用 + 运算符进行字符串连接std::string result1 = str1 + str2;std::cout << result1 << std::endl;  // 输出: Hello World!// 使用 += 运算符进行字符串连接str1 += str2;std::cout << str1 << std::endl;      // 输出: Hello World!return 0;
}
运算符重载的优点
  1. 可读性:通过运算符重载,字符串的拼接可以像数学运算那样直观,增加了代码的可读性。
  2. 灵活性:除了基本的字符串拼接,开发者可以根据需要重载其他运算符,实现自定义的字符串功能。
  3. 一致性:运算符重载使得字符串操作与其他内置类型在语法上保持一致,降低了学习成本。
注意事项

尽管运算符重载提供了许多优势,但滥用这种特性可能会导致代码可读性降低。因此,开发者在实现运算符重载时应注意遵循一致性和直观性的原则。

Java 的 StringBuilder

在 Java 中,String 类是不可变的(immutable),这意味着每次修改字符串时都会创建一个新的对象。这在某些情况下可能会导致性能问题,尤其是在需要进行大量字符串拼接操作时。为了解决这个问题,Java 提供了 StringBuilder 类。

StringBuilder 的特点
  • 可变性:与 String 不同,StringBuilder 对象是可变的,允许在不创建新对象的情况下修改字符串内容。
  • 高效性:在进行字符串拼接或大量字符串操作时,StringBuilder 的性能优于 String,因为它减少了内存分配和垃圾回收的开销。
示例代码
public class StringBuilderExample {public static void main(String[] args) {StringBuilder sb = new StringBuilder("Hello");// 使用 append 方法进行字符串拼接sb.append(" World!");System.out.println(sb.toString());  // 输出: Hello World!// 可以继续在同一对象上进行拼接sb.append(" Welcome to Java.");System.out.println(sb.toString());  // 输出: Hello World! Welcome to Java.}
}
StringBuilder 的优点
  1. 性能优化StringBuilder 在字符串操作时减少了对象的创建和销毁,因此在进行大量拼接时性能更好。
  2. 灵活控制StringBuilder 提供了丰富的方法,如 append()insert()delete() 等,这些方法使得字符串的操作更加灵活。
  3. 适用于多线程:若需要在多线程环境中使用,可以使用 StringBuffer,它与 StringBuilder 类似,但提供了同步(thread-safe)机制,适合在并发环境中使用。
使用注意事项
  • 当使用 StringBuilder 时,若不需要在多线程环境中进行操作,尽量选择 StringBuilder 而非 StringBuffer,因为后者会有额外的性能开销。
  • 如果字符串拼接或修改操作较少,可以考虑使用 String 类以简化代码。
总结

C++ 的运算符重载和 Java 的 StringBuilder 类在字符串操作的实现上各有千秋。C++ 利用运算符重载提高了字符串拼接的可读性和灵活性,而 Java 的 StringBuilder 则在字符串操作性能上表现突出。通过掌握这些工具和技巧,开发者可以在不同的编程语言中高效地处理字符串,从而提升代码质量与执行效率。

4. 线程安全

在现代编程中,多线程环境已成为常态。对于共享资源的访问与操作,如果没有适当的控制,可能会导致数据不一致或程序崩溃。因此,了解不同编程语言中对字符串的线程安全设计非常重要。以下是 C++ 和 Java 中字符串处理的线程安全机制的详细说明。

C++ 的线程安全性

在 C++ 中,标准库(如 std::string)并未自动提供线程安全保障。这意味着,如果多个线程同时访问和修改同一个 std::string 对象,开发者需要自行吸取控制和同步机制,确保字符串的安全访问。

1. 线程安全的挑战

  • 数据竞态:当多个线程同时读取和写入一个 std::string 对象时,可能会出现竞态条件(race condition),导致数据不一致或程序崩溃。
  • 不确定性:如果没有合理的锁定机制,可以在未完全写入的情况下读取字符串,造成读取脏数据。

2. 自行实现同步

C++ 通常通过使用互斥锁(mutexes)来确保线程安全。开发者需要在访问 std::string 对象的代码块周围加锁,确保只有一个线程能访问该对象。

示例代码

#include <iostream>
#include <string>
#include <thread>
#include <mutex>std::string sharedString;
std::mutex mtx; // 互斥锁void appendToString(const std::string& str) {std::lock_guard<std::mutex> lock(mtx); // 加锁sharedString += str; // 修改共享字符串
}int main() {std::thread t1(appendToString, "Hello");std::thread t2(appendToString, ", World!");t1.join();t2.join();std::cout << sharedString << std::endl; // 可能输出: Hello, World!return 0;
}
其他线程安全的解决方案
  • 使用一定的设计模式,如生产者-消费者模式。
  • 使用std::atomic,适合简单数据的无锁并发。
Java 的线程安全性

在 Java 中,String 类是不可变的(immutable),这意味着一旦创建了字符串对象,其内容不能被改变。这种设计使得 Java 字符串在多线程环境中自然而然地具备了线程安全特性。

1. 不可变的特性

  • 共享安全:因为 String 对象不可变,多个线程可以安全地读取同一字符串实例,而无须担心会被其他线程修改,从而引发数据竞争问题。
  • 内存优化:不可变字符串可以被 JVM 重用,这减少了内存消耗,并提高了性能。

2. 多线程环境下的应用

在Java多线程操作中,String 使用非常广泛,尤其是在处理共享数据的场景。

示例代码

public class ThreadSafeStringExample {public static void main(String[] args) {String sharedString = "Hello";Runnable task = () -> {String anotherString = sharedString + ", World!";System.out.println(anotherString);};Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();}
}
处理可变字符串的情况
  • 当需要进行频繁的字符串修改时,可以使用 StringBuilderStringBuffer
  • StringBuffer 是线程安全的,其内部方法采用同步机制来确保多线程访问的安全性,但其性能相对较低。此外,StringBuilder 在单线程环境中使用,提供了更好的性能,因为它没有同步开销。
总结

在 C++ 和 Java 之间,存在着关于线程安全设计的显著差异:

  • C++

    • 不支持自动线程安全,开发者需要使用锁机制等手动同步方法来保护 std::string 对象。
    • 需自行实现多线程安全的访问控制,增加了代码复杂性和潜在出错的风险。
  • Java

    • String 类的不可变性使得在多线程环境中天然线程安全。
    • 操作简单,不亟需担心字符串在并发环境中的安全性。
    • 在需要可变字符串时,推荐使用 StringBuffer 来确保线程安全,但也要注意性能影响。

理解这两种语言中线程安全的设计,能够帮助开发者选择最佳的字符串处理方式,从而有效地应对多线程环境带来的挑战。在构建稳定的并发应用时,选择合适的工具和设计模式至关重要。

5. 字符串操作的跨语言对比

在讨论了 C++ 和 Java 中字符串操作的不同之处后,我也学习了一些其他的编程语言,所以将其与其他编程语言如 Python、JavaScript 和 C# 进行比较,以便更全面地理解字符串处理的多样性和灵活性。

Python 的字符串处理

不可变字符串

  • Python 中的字符串是不可变的(immutable),类似于 Java 的 String 类。每次修改字符串时,都会生成一个新的字符串对象。

丰富的操作方法

  • Python 字符串提供了多种内置方法,如 join()split()replace() 和格式化方法(如 f-string),使字符串操作变得非常方便。

拼接操作

  • 字符串拼接可以使用 + 操作符或者 join() 方法,而 join() 方法在拼接大量字符串时性能更佳。
示例代码
str1 = "Hello"
str2 = " World!"
result = str1 + str2  # 使用 + 操作符
print(result)  # 输出: Hello World!# 使用 join() 方法
words = ["Hello", "World!"]
sentence = ' '.join(words)
print(sentence)  # 输出: Hello World!
JavaScript 的字符串处理

不可变字符串

  • JavaScript 中的字符串同样是不可变的。每次修改字符串时,都会创建一个新的字符串。

模板字符串

  • JavaScript 引入了模板字符串(Template Literals),使用反引号(`)包裹字符串,允许在字符串中嵌入表达式,提高了字符串拼接的灵活性和可读性。
示例代码
let str1 = "Hello";
let str2 = "World!";
let result = `${str1} ${str2}`;  // 使用模板字符串
console.log(result);  // 输出: Hello World!
C# 的字符串处理

不可变字符串

  • C# 的字符串与 Java 和 Python 一样也是不可变的(immutable)。

StringBuilder 类

  • C# 也提供了 StringBuilder 类,功能与 Java 中的 StringBuilder 类似,适用于在多次字符串修改时提高性能。

字符串插值

  • C# 通过字符串插值(String Interpolation)允许在字符串中嵌入变量,语法使用 $ 符号。
示例代码
using System;
using System.Text;class Program
{static void Main(){StringBuilder sb = new StringBuilder("Hello");sb.Append(" World!");Console.WriteLine(sb.ToString());  // 输出: Hello World!// 字符串插值string name = "World";string greeting = $"Hello, {name}!";  // 使用字符串插值Console.WriteLine(greeting);  // 输出: Hello, World!}
}
总结跨语言比较

预先定义的字符串操作特性和性能在不同编程语言中有显著的差异和共同点:

  1. 不可变性:大多数现代编程语言(如 Java, Python, JavaScript, C#)都将字符串设计为不可变的,这提高了安全性和线程安全性。

  2. 操作方法的丰富性:不同语言在字符串处理上提供了丰富的操作方法。在 Python 中,有 join()split();在 JavaScript 中,模板字符串可以直接拼接;而 C# 则强调字符串插值与 StringBuilder 的高效性。

  3. 性能优化:C++ 和 Java 的 StringBuilder 类都通过可变性优化了大量字符串拼接的性能,相对而言,Python 和 JavaScript 的不可变字符串在进行大量拼接时性能可能较低,因此需要仔细考虑。

  4. 语言设计哲学:不同语言在字符串的设计上反映了其整体设计哲学。例如,C++ 传统上给予开发者更多的控制权,而 Python 则更注重可读性与简洁性。

6. 字符串转换为数组:Java、Python 和 JavaScript 的常用方法

在处理数据时,有时需要将字符串转换为数组 (或列表),以便进行进一步的操作。不同编程语言提供了不同的方法来实现这一转换。下面我们将详细探讨 Java、Python 和 JavaScript 中如何将字符串转换为数组,并通过示例展示基本的数据处理操作。

Java 中的字符串转换为数组
方法一:

在 Java 中,可以使用 String 类的 split() 方法将字符串分割成数组。

示例代码

public class StringToArrayExample {public static void main(String[] args) {String str = "apple,banana,cherry";// 使用 split() 方法将字符串转换为数组String[] fruits = str.split(","); // 以逗号分隔// 输出数组内容for (String fruit : fruits) {System.out.println(fruit);}// 处理数据:统计数组长度System.out.println("Number of fruits: " + fruits.length); // 输出: 3}
}
方法二:

在 Java 中,您可以使用 String 类的 toCharArray() 方法将字符串转换为字符数组。这个方法会返回一个新的字符数组,其中包含字符串中的每个字符。

示例代码

public class StringToCharArrayExample {public static void main(String[] args) {String s = "hello";// 使用 toCharArray() 方法将字符串转换为字符数组char[] t = s.toCharArray();// 输出字符数组内容for (char c : t) {System.out.println(c);}// 数据处理:统计元音字母个数int vowelCount = 0;for (char c : t) {if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {vowelCount++;}}System.out.println("Number of vowels: " + vowelCount); // 输出: 2}
}
Python 中的字符串转换为列表
方法一:

在 Python 中,使用 split() 方法也可以将字符串转换为列表。

示例代码

str_value = "apple,banana,cherry"# 使用 split() 方法将字符串转换为列表
fruits = str_value.split(",")  # 以逗号分隔# 输出列表内容
for fruit in fruits:print(fruit)# 数据处理:统计列表长度
print("Number of fruits:", len(fruits))  # 输出: 3
方法二:

在 Python 中,可以使用 list() 函数将字符串转换为列表,该列表中的每个元素都是字符串中的一个字符。

示例代码

s = "hello"# 使用 list() 函数将字符串转换为字符列表
t = list(s)# 输出字符列表内容
for c in t:print(c)# 数据处理:统计元音字母个数
vowel_count = sum(1 for c in t if c in 'aeiou')
print("Number of vowels:", vowel_count)  # 输出: 2
JavaScript 中的字符串转换为数组

在 JavaScript 中,可以使用 split() 方法将字符串转换为数组。

示例代码

let str = "apple,banana,cherry";// 使用 split() 方法将字符串转换为数组
let fruits = str.split(","); // 以逗号分隔// 输出数组内容
fruits.forEach((fruit) => {console.log(fruit);
});// 数据处理:统计数组长度
console.log("Number of fruits:", fruits.length); // 输出: 3

相关文章:

字符串的区别

C 和 Java 字符串的区别 最近 C 和 Java 在同步学习&#xff0c;都有个字符串类型&#xff0c;但二者不太一样&#xff0c;于是就做了些许研究。 在编程中&#xff0c;字符串作为数据类型广泛应用于不同的场景。虽然 C 和 Java 都允许我们处理字符串&#xff0c;但它们在字符…...

EMR Serverless Spark:一站式全托管湖仓分析利器

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 李钰&#xff08;绝顶&#xff09; | 阿里云智能集团资深技术专家&#xff0c;阿里云 EMR 团队负责人 活动&#xff1a; 2024 云栖大会 AI - 开源大数据专场 数据平台技术演变 …...

Linux find 匹配文件内容

在Linux中&#xff0c;你可以使用find命令结合-exec或者-execgrep来查找匹配特定内容的文件。以下是一些示例&#xff1a; 查找当前目录及其子目录下所有文件内容中包含"exampleText"的文件&#xff1a; find . -type f -exec grep -l "exampleText" {} \…...

【Redis优化——如何优雅的设计key,优化BigKey,Pipeline批处理Key】

Redis优化——如何优雅的设计key&#xff0c;优化BigKey&#xff0c;Pipeline批处理Key 一、Key的设计1. 命名规范2. 长度限制在44字节以内 二、BigKey优化1. 查找bigkey2. 删除BigKey3. 优化BigKey 三、Pipeline批处理Key1. 单节点的Pipeline2. 集群下的Pipeline 一、Key的设计…...

数据结构与算法分析:你真的理解图算法吗——深度优先搜索(代码详解+万字长文)

一、前言 图是计算机科学中用来表示复杂结构信息的一种基本结构。本章我们会讨论一些通用的围表示法,以及一些频繁使用的图算法。本质上来说,一个图包含一个元素集合(也就是顶点),以及元素两两之间的关系(也就是边),由于应用范围所限,本章我们仅仅讨论简单图,简单围并不会如(a…...

LinkedList 分析

LinkedList 简介 LinkedList 是一个基于双向链表实现的集合类&#xff0c;经常被拿来和 ArrayList 做比较。关于 LinkedList 和ArrayList的详细对比&#xff0c;我们 Java 集合常见面试题总结(上)有详细介绍到。 双向链表 不过&#xff0c;我们在项目中一般是不会使用到 Link…...

【C/C++】模拟实现strlen

学习目标&#xff1a; 使用代码模拟实现strlen。 逻辑&#xff1a; strlen 需要输入一个字符串数组类型的变量&#xff0c;并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1&#xff1a;使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…...

mybatis从浅入深一步步演变分析

mybatis从浅入深一步步演变分析 版本一&#xff1a;不使用代理&#xff08;非spring&#xff09; package com.yimeng.domain;public class User {private int id;private String username;private String password;public int getId() {return id;}public void setId(int id…...

Java阶段三02

第3章-第2节 一、知识点 面向接口编程、什么是spring、什么是IOC、IOC的使用、依赖注入 二、目标 了解什么是spring 理解IOC的思想和使用 了解IOC的bean的生命周期 理解什么是依赖注入 三、内容分析 重点 了解什么是spring 理解IOC的思想 掌握IOC的使用 难点 理解IO…...

【Linux】掌握库的艺术:我的动静态库封装之旅

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.什么是库1.2 认识动静态库1.2.1 动态库1.2.2…...

UE5动画控制 基础

素材 mixamo先去选择一个character 点击下载 就这个下载下来 然后选几个animation&#xff0c; 记得勾选 把动作下载了 without skin就是只要动作 然后把他们放在一个文件夹里先 UE里导入 找一个文件夹&#xff0c;直接拖拽进来那个character的fbx&#xff0c;默认配置就…...

流畅!HTMLCSS打造网格方块加载动画

效果演示 这个动画的效果是五个方块在网格中上下移动&#xff0c;模拟了一个连续的加载过程。每个方块的动画都是独立的&#xff0c;但是它们的时间间隔和路径被设计为相互协调&#xff0c;以创建出流畅的动画效果。 HTML <div class"loadingspinner"><…...

linux命令之top(Linux Command Top)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…...

数据结构-希尔排序(ShellSort)笔记

看动画理解 【数据结构】八大排序(超详解附动图源码)_数据结构排序-CSDN博客 一 基本思想 先选定一个整数gap&#xff0c;把待排序文件中所有记录分成gap个组&#xff0c;所有距离为gap的记录分在同一组内&#xff0c;并对每一组内的元素进行排序。 然后将gap逐渐减小重复上…...

Junit + Mockito保姆级集成测试实践

一、做好单测&#xff0c;慢即是快 对于单元测试的看法&#xff0c;业界同仁理解多有不同&#xff0c;尤其是在业务变化快速的互联网行业&#xff0c;通常的问题主要有&#xff0c;必须要做吗&#xff1f;做到多少合适&#xff1f;现在没做不也挺好的吗&#xff1f;甚至一些大…...

软件项目管理要点

一.项目管理 1.盈亏平衡分析 销售额固定成本可变成本税费利润 当利润为0的时候就是盈亏平衡点。 2.范围管理 范围定义的输入包括&#xff1a;项目章程、项目范围管理计划、组织过程资产、批准的变更申请。 3.时间管理 项目时间管理中的过程包括活动定义、活动排序、活动的资…...

ESP8266 连接 MQTT 服务器EMQX 连接MQTTX

目录 1.先用有一台自己的云服务器 2. 使用FinalShell连接阿里云云服务器ECS 3.安装宝塔 4.在云服务器打开8888端口 5.使用外网面板地址打开宝塔面板 6.安装Docker 7.下载emqx 8.打开emqxWeb 界面 9.下载MQTTX 10.EMQX加一个客户端 11.开始通信 12.加入单片机ESP8266 …...

Python中如何处理异常情况?

1、Python中如何处理异常情况&#xff1f; 在Python中&#xff0c;处理异常情况通常使用try/except语句。try语句块包含可能会引发异常的代码&#xff0c;而except语句块包含处理异常的代码。如果try块中的代码引发了异常&#xff0c;控制流将立即转到相应的except块。 以下是…...

openpnp - 在openpnp中单独测试相机

文章目录 openpnp - 在openpnp中单独测试相机概述笔记END openpnp - 在openpnp中单独测试相机 概述 底部相机的位置不合适, 重新做了零件&#xff0c;准备先确定一下相机和吸嘴的距离是多少才合适。 如果在设备上直接实验&#xff0c;那么拆装调整相机挺麻烦的。 准备直接在电…...

Spark窗口函数

1、 Spark中的窗口函数 窗口就是单纯在行后面加一个列 可以套多个窗口函数&#xff0c;但彼此之间不能相互引用&#xff0c;是独立的 窗口函数会产生shuffle over就是用来划分窗口的 (1) 分组聚合里面的函数&#xff0c;基…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...