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

Java常用类-String三剑客

目录

  • 一、核心差异总结(先看结论)
  • 二、String类(不可变的秘密)
    • 1. 源码关键设计
      • 1.1关键差异总结
    • 2. 内存管理机制
      • 2.1各个迭代版本的区别
        • Java 6及之前
          • 示例代码(Java 6):
        • Java 7
        • Java 8
        • Java 9
          • 源码示例(Java 9+):
        • Java 11
          • 示例代码:
        • Java 12+
        • Java 15+
      • 2.2内存占用对比
      • 2.3总结:各版本内存管理重点
      • 2.4优化建议
    • 3.常用方法
      • 3.1 字符串拼接与替换
      • 3.2 查找与截取
      • 3.3 大小写转换与空白处理
      • 3.4 分割与匹配
  • 三、StringBuilder(单线程王者)
    • 1. 存储结构:char[] 动态扩容
      • 源码关键部分:
    • 2. 动态扩容机制
      • 源码关键部分:
    • 3. 核心方法:append() 的实现
      • 源码关键部分:
      • 高效操作原理
    • 4. 线程不安全设计
      • 对比示例:
    • 5. 字符编码优化(Java 9+)
      • 源码关键部分:
    • 6. toString() 方法的优化
      • 源码关键部分:
    • 核心性能优势
    • 使用建议
  • 四、StringBuffer(多线程卫士)
    • 1. 继承结构与存储设计
      • 源码关键部分:
    • 2. 线程安全实现
      • 示例对比:
    • 3. 动态扩容机制
      • 源码关键部分:
    • 4. 字符编码优化(Java 9+)
      • 源码关键部分:
    • 5. 同步开销与性能权衡
      • 性能测试示例(单线程场景):
    • 6. 特殊方法实现
      • 源码关键部分:
  • 五、StringBuffer和StringBuilder两者扩容机制详解
    • 1. 存储结构与编码优化
      • 源码关键部分:
    • 2. 核心扩容逻辑
      • 源码关键部分:
    • 3. 编码感知的容量计算
      • 源码关键部分:
    • 总结:JDK 17+ 扩容机制的核心特点
  • 六、StringBuffer/StringBuilder 常用方法
    • 1. 追加与插入
    • 2. 删除与替换
    • 3. 反转与容量管理
    • 4. 转换为String
  • 七、三者对比表
  • 八、终极使用策略
    • 1.String​​:
    • 2.StringBuilder​​:
    • 3.StringBuffer​​:
    • 使用场景建议
  • 一句话记忆口诀

深入解析Java字符串三剑客:String、StringBuilder、StringBuffer

一、核心差异总结(先看结论)

可变性线程安全性能适用场景
​​String​​❌ 不可变✅ 安全最差少量字符串操作
​​StringBuilder​​ ✅ 可变❌ 不安全最高 ​​单线程​​频繁修改
​​StringBuffer​​ ✅ 可变✅ 安全中等 ​​多线程​​环境

二、String类(不可变的秘密)

1. 源码关键设计

//Java 17+ 密封类声明(强调不可继承性)
public final class String implements Serializable, Comparable<String>, CharSequence, Constable, ConstantDesc {@Stable// Java9 存储字符串值的字节数组(关键!final修饰的不可变数组)private final byte[] value;    // Java9改用byte数组存储private final byte coder;      // 0=LATIN1, 1=UTF16private int hash;              // 哈希缓存// Java7 substring方法(不共享数组,复制新数组)public String substring(int beginIndex, int endIndex) {int subLen = endIndex - beginIndex;char[] sub = new char[subLen];System.arraycopy(value, beginIndex, sub, 0, subLen);return new String(sub, false);}// Java9构造函数(根据内容选择编码)public String(char[] value, int offset, int count) {this.value = StringUTF16.compress(value, offset, count);this.coder = this.value == null ? UTF16 : LATIN1;}// Java9 charAt方法(需根据coder处理)public char charAt(int index) {if (isLatin1()) {return (char)(value[index] & 0xff);} else {return StringUTF16.charAt(value, index);}}// Java11 新增repeat方法public String repeat(int count) {if (count < 0) {throw new IllegalArgumentException();}if (count == 1) {return this;}int len = length();if (len == 0 || count == 0) {return "";}// ...省略数组复制逻辑}//Java11 新增isBlank方法public boolean isBlank() {for (int i = 0; i < value.length; i++) {if (!Character.isWhitespace(value[i])) {return false;}}return true;}
} 
  • ​​所有修改操作​​(如concat、replace)都会创建新String对象
  • 例子:String s = “a”; s += “b”; → 实际产生2个对象(“a"和"ab”)

1.1关键差异总结

版本核心改动点
Java 6char[] value + offset/count(子串共享数组)
Java 7移除 offset/count,substring 复制新数组
Java 9byte[] value + coder(Latin-1/UTF-16 动态编码)
Java 11新增 repeat()、isBlank()、strip() 等实用方法
Java 15+密封类声明,强制 final(实际自 Java 1 即不可继承)

这些改动体现了 Java 对内存效率(如 Latin-1 单字节存储)和 API 易用性(如repeat方法)的持续优化。

2. 内存管理机制

String 的内存管理机制在不同版本中都经历了重大变革,主要围绕节省内存、减少GC压力和优化字符串常量池展开。

2.1各个迭代版本的区别

Java 6及之前
  • 存储结构:使用char[] value存储字符,每个字符占2字节(UTF-16),即使仅包含ASCII字符也需2字节。
  • 字符串常量池:位于永久代(PermGen),空间固定(默认 64MB),无法动态扩容,易导致OutOfMemoryError: PermGen space。
  • substring 内存泄漏风险:子串与原字符串共享char[],即使原字符串不再使用,数组也无法被GC(示例如下)。
示例代码(Java 6):
String str = "abcdefghijklmnopqrstuvwxyz";
String sub = str.substring(0, 2); // sub仅需2字符,但共享原数组(26字符)
// str不再使用,但原char[]无法被回收
Java 7
  • 字符串常量池迁移:从永久代移至堆内存(Heap),避免永久代溢出,可通过-Xmx参数调整堆大小。
  • substring优化:不再共享原char[],而是复制新数组,解决内存泄漏问题,但可能增加内存使用(每次截取都创建新数组)。
Java 8
  • 永久代移除:引入元空间(Metaspace)替代永久代,字符串常量池仍在堆中。
  • 压缩指针优化(Compressed OOPs):对象指针压缩为32 位,减少内存开销。
Java 9
  • 字符串常量池优化
    - 1)启动时预加载常用字符串(如JDK内部字符串)。
    - 2)新增-XX:StringTableSize 参数调整哈希表大小(默认 60013),减少哈希冲突。
  • 革命性存储结构byte[] + coder
    将 char[] 改为 byte[],并新增 coder 字段标记编码:
    - 1)LATIN1(单字节,占 1 字节 / 字符):存储 ASCII 字符(最常见场景)。
    - 2)UTF16(双字节,占 2 字节 / 字符):存储非 ASCII 字符(如中文、 emoji)。
    内存节省:对于纯 ASCII 字符串,内存占用减少 50%。
源码示例(Java 9+):
public final class String {private final byte[] value;  // 存储字节private final byte coder;    // 0=LATIN1, 1=UTF16public char charAt(int index) {return coder == LATIN1 ? (char)(value[index] & 0xff) :  // Latin-1解码StringUTF16.charAt(value, index);  // UTF-16解码}
}
Java 11
  • G1 GC字符串去重(默认开启)
    通过 -XX:+UseStringDeduplication 参数,让G1在GC时自动检测并合并内容相同的字符串(通过byte[]比较),进一步节省内存。
示例代码:
String s1 = new String("hello");
String s2 = new String("hello");
// 经G1去重后,s1和s2可能指向同一byte[]
Java 12+
  • Shenandoah GC优化
    对字符串常量池的并发标记和回收更高效,减少STW(Stop The World)时间。
  • ZGC支持(Java 15+)
    处理大堆(TB 级)时,字符串常量池的管理性能显著提升。
Java 15+
  • Compact Strings 成为默认:Java 9 引入的 byte[] 存储方案完全稳定,无法通过参数关闭。
  • 字符串常量池动态调整
    JVM 会根据运行时情况自动调整字符串常量池的哈希表大小,减少内存碎片。

2.2内存占用对比

版本存储方式纯 ASCII 字符串(100 字符)包含中文的字符串(50 中文 + 50 英文)
Java 6char[]200 字节300 字节
Java 9byte[]100 字节(节省 50%)200 字节(节省 33%)

2.3总结:各版本内存管理重点

版本核心改进点
Java 6永久代常量池,substring共享数组导致内存泄漏
Java 7常量池移至堆,substring复制数组
Java 8移除永久代,引入元空间
Java 9byte[] + coder 存储,字符串常量池哈希表优化
Java 11G1 GC字符串去重,减少重复字符串内存占用
Java 15+Compact Strings强制启用,ZGC优化大堆字符串管理

2.4优化建议

  • 优先使用 Java 9+:利用 byte[] 存储节省内存。
  • 避免大字符串频繁截取:Java 7+ 虽修复内存泄漏,但复制数组仍有开销。
  • 控制字符串常量池大小:通过 -XX:StringTableSize 优化哈希表性能。
  • 启用字符串去重(Java 11+):对重复字符串多的场景(如缓存、日志),开启 -XX:+UseStringDeduplication。
  • 避免手动 intern():除非明确需要共享字符串(如缓存键),否则可能增加 GC 压力。

3.常用方法

String 是不可变类,所有修改操作都会返回新的 String 对象。

3.1 字符串拼接与替换

String s = "Hello";// 拼接
String s1 = s.concat(" World");  // "Hello World"
String s2 = s + " Java";         // "Hello Java"// 替换
String s3 = s.replace('e', 'a');  // "Hallo"
String s4 = s.replaceAll("ll", "yy");  // "Heyylo"

3.2 查找与截取

String s = "HelloWorld";// 查找
int index = s.indexOf("World");  // 5
boolean contains = s.contains("lo");  // true// 截取
String sub = s.substring(5);  // "World"
String sub2 = s.substring(0, 5);  // "Hello"

3.3 大小写转换与空白处理

String s = "  Hello  ";// 大小写
String upper = s.toUpperCase();  // "  HELLO  "
String lower = s.toLowerCase();  // "  hello  "// 空白处理
String trimmed = s.trim();  // "Hello" (Java 11+ 可用 strip())

3.4 分割与匹配

String s = "a,b,c";// 分割
String[] parts = s.split(",");  // ["a", "b", "c"]// 正则匹配
boolean isNum = "123".matches("\\d+");  // true

三、StringBuilder(单线程王者)

1. 存储结构:char[] 动态扩容

StringBuilder内部使用char[]数组存储字符序列,并通过count字段记录当前实际长度。数组会在容量不足时动态扩容。

源码关键部分:

abstract class AbstractStringBuilder {char[] value;  // ← 关键!没有final修饰,可扩容int count;     // 实际字符数量AbstractStringBuilder(int capacity) {value = new char[capacity];  // 初始容量}
}
public final class StringBuilder extends AbstractStringBuilder {public StringBuilder() {super(16);  // 默认初始容量为16}// 所有方法都没有synchronized修饰!@Overridepublic StringBuilder append(String str) {super.append(str);return this;}
}

2. 动态扩容机制

当追加内容导致容量不足时,会触发扩容逻辑:

  • 计算新容量(通常为原容量的2倍 + 2)。
  • 创建新数组并复制原有内容。
  • 丢弃原数组,指向新数组。

源码关键部分:

abstract class AbstractStringBuilder {private void ensureCapacityInternal(int minimumCapacity) {if (minimumCapacity - value.length > 0) {value = Arrays.copyOf(value, newCapacity(minimumCapacity));}}private int newCapacity(int minCapacity) {int oldCapacity = value.length;int newCapacity = oldCapacity * 2 + 2;  // 关键公式:2倍+2if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;  // 至少满足最小需求}return newCapacity;}
}

3. 核心方法:append() 的实现

append() 是最常用的方法,支持追加各种类型的数据。其核心逻辑是:

  • 检查容量是否足够,不足则扩容。
  • 将数据转换为字符并复制到value数组。

源码关键部分:

public AbstractStringBuilder append(String str) {if (str == null) return appendNull();  // 处理nullint len = str.length();ensureCapacityInternal(count + len);  // 确保容量足够str.getChars(0, len, value, count);  // 复制字符到value数组count += len;  // 更新实际长度return this;
}

高效操作原理

StringBuilder sb = new StringBuilder();
sb.append("A").append("B"); // 始终操作同一个对象
  • 链式调用​​:方法返回this对象,支持链式编程
  • ​​扩容示例​​:
    • 初始:char[16]
    • 追加17个字符 → 扩容到(16 * 2)+2=34

4. 线程不安全设计

StringBuilder不保证线程安全,所有方法均未加锁。相比之下,StringBuffer通过synchronized修饰方法保证线程安全,但性能较低。

对比示例:

// StringBuilder(线程不安全,性能高)
public StringBuilder append(String str) {// 无同步操作
}// StringBuffer(线程安全,性能低)
public synchronized StringBuffer append(String str) {// 同步块
}

5. 字符编码优化(Java 9+)

Java 9 及以后,StringBuilder与String保持一致,改用byte[]存储:

  • Latin-1 编码:单字节存储 ASCII 字符。
  • UTF-16 编码:双字节存储其他字符。

源码关键部分:

abstract class AbstractStringBuilder {byte[] value;byte coder;  // 0=LATIN1, 1=UTF16// 根据内容选择编码private void ensureCapacityInternal(int minimumCapacity) {if (nonLatin1(capacity)) {value = new byte[newCapacity(minimumCapacity)];coder = UTF16;} else {value = new byte[newCapacity(minimumCapacity)];coder = LATIN1;}}
}

6. toString() 方法的优化

toString() 会创建新的String对象,但通过复用char[]或byte[]避免重复复制:

源码关键部分:

public String toString() {// 创建新String对象,复用内部数组(Java 9+使用byte[])return isLatin1() ?new String(value, LATIN1) :new String(value, UTF16);
}

核心性能优势

  • 避免频繁创建对象:通过动态扩容减少内存分配和垃圾回收。
  • 直接操作数组:append() 等方法通过System.arraycopy() 高效复制数据。
  • 无同步开销:线程不安全设计避免了锁竞争。

使用建议

  • 预分配容量:已知大致长度时,通过new StringBuilder(initialCapacity) 减少扩容次数。
  • 循环外创建实例:避免在循环中重复创建StringBuilder。

反例:

for (int i = 0; i < 1000; i++) {StringBuilder sb = new StringBuilder();  // 每次循环创建新对象sb.append(i);
}

正例:

StringBuilder sb = new StringBuilder();  // 在循环外创建
for (int i = 0; i < 1000; i++) {sb.append(i);
}

四、StringBuffer(多线程卫士)

1. 继承结构与存储设计

StringBuffer继承自AbstractStringBuilder,与StringBuilder共享存储逻辑,但所有公开方法均被synchronized修饰以保证线程安全。

源码关键部分:

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable {// 继承AbstractStringBuilder的字段// char[] value;  // 存储字符的数组// int count;     // 实际字符数量public StringBuffer() {super(16);  // 默认初始容量16}
}

2. 线程安全实现

所有修改操作(如append、insert)均被synchronized修饰,确保同一时间只有一个线程能修改内部状态。

示例对比:

// StringBuffer(线程安全)
public synchronized StringBuffer append(String str) {super.append(str);return this;
}// StringBuilder(线程不安全)
public StringBuilder append(String str) {super.append(str);return this;
}

3. 动态扩容机制

与StringBuilder完全相同,通过ensureCapacityInternal() 和newCapacity() 实现数组动态扩容,默认扩容为2倍 + 2。

源码关键部分:

abstract class AbstractStringBuilder {private void ensureCapacityInternal(int minimumCapacity) {if (minimumCapacity - value.length > 0) {value = Arrays.copyOf(value, newCapacity(minimumCapacity));}}private int newCapacity(int minCapacity) {int newCapacity = (value.length << 1) + 2;  // 2倍+2// ... 其他边界处理}
}

4. 字符编码优化(Java 9+)

Java 9及以后,与String和StringBuilder一致,改用byte[]存储:

  • Latin-1 编码:单字节存储 ASCII 字符。
  • UTF-16 编码:双字节存储其他字符。

源码关键部分:

abstract class AbstractStringBuilder {byte[] value;byte coder;  // 0=LATIN1, 1=UTF16// 根据内容选择编码private void ensureCapacityInternal(int minimumCapacity) {if (nonLatin1(capacity)) {value = new byte[newCapacity(minimumCapacity)];coder = UTF16;} else {value = new byte[newCapacity(minimumCapacity)];coder = LATIN1;}}
}

5. 同步开销与性能权衡

synchronized修饰导致的锁竞争会带来显著性能开销,尤其在高并发场景下。测试数据显示(单线程场景),StringBuffer的单线程性能比StringBuilderda低20%-50%。

性能测试示例(单线程场景):

	@Test//约为38mspublic void test1() {long startTime = System.currentTimeMillis();StringBuilder sb = new StringBuilder();for (int i = 0; i < 10000000; i++) {sb.append("a");}long endTime = System.currentTimeMillis();System.out.println(endTime - startTime);}@Test//约为212mspublic void test2() {long startTime = System.currentTimeMillis();StringBuffer sb = new StringBuffer();for (int i = 0; i < 10000000; i++) {sb.append("a");}long endTime = System.currentTimeMillis();System.out.println(endTime - startTime);}

6. 特殊方法实现

toStringCache 字段
StringBuffer维护一个缓存字段toStringCache,用于暂存最后一次toString() 的结果。当对象被修改时,该缓存会被清空。

源码关键部分:

public final class StringBuffer {private transient char[] toStringCache;  // 缓存toString()结果@Overridepublic synchronized String toString() {if (toStringCache == null) {toStringCache = Arrays.copyOfRange(value, 0, count);}return new String(toStringCache, true);}@Overridepublic synchronized StringBuffer append(String str) {toStringCache = null;  // 修改时清空缓存super.append(str);return this;}
}

五、StringBuffer和StringBuilder两者扩容机制详解

1. 存储结构与编码优化

自JDK 9起,两者均使用byte[]替代char[],并通过coder字段标记编码类型:

  • Latin-1(单字节):存储 ASCII 字符(占 1 字节 / 字符)。
  • UTF-16(双字节):存储非 ASCII 字符(如中文、emoji)。

源码关键部分:

abstract class AbstractStringBuilder implements Appendable, CharSequence {byte[] value;      // 存储字节数据byte coder;        // 0=LATIN1, 1=UTF16int count;         // 实际字符数量(非字节数)// 返回容量(字节数)final int capacity() {return value.length;}
}

2. 核心扩容逻辑

注意:StringBuilder/StringBuffer的length()返回的是count,不是value.length。
例如:sb.length() == 5 但底层数组可能是char[34]

当追加内容导致容量不足时,会触发 ensureCapacityInternal() 方法:

源码关键部分:

private void ensureCapacityInternal(int minimumCapacity) {// 如果当前容量不足if (minimumCapacity - value.length > 0) {value = Arrays.copyOf(value, newCapacity(minimumCapacity));}
}private int newCapacity(int minCapacity) {// 旧容量加倍 + 2(核心扩容公式)int newCapacity = (value.length << 1) + 2;// 确保新容量至少满足最小需求if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;}// 检查是否超过最大数组大小(Integer.MAX_VALUE - 8)return hugeCapacity(minCapacity);
}private int hugeCapacity(int minCapacity) {if (Integer.MAX_VALUE - minCapacity < 0) {throw new OutOfMemoryError();}return (minCapacity > MAX_ARRAY_SIZE) ?minCapacity :MAX_ARRAY_SIZE;
}
  • 关键点:
    • 默认扩容公式:新容量 = 旧容量 × 2 + 2。
  • 边界处理:
    • 若新容量小于所需最小容量,直接使用最小容量。
    • 若新容量超过 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),则尝试使用minCapacity,但可能触发 OutOfMemoryError。

3. 编码感知的容量计算

在计算容量时,需根据 coder 类型(Latin-1/UTF-16)调整字节数:

源码关键部分:

// 追加String时的容量计算
public AbstractStringBuilder append(String str) {if (str == null) return appendNull();int len = str.length();ensureCapacityInternal(count + len);  // 按字符数计算最小容量str.getBytes(value, coder, count);    // 按实际编码存储count += len;return this;
}
  • 关键点:
    • ensureCapacityInternal(count + len) 按字符数计算最小容量。
    • 实际存储时,getBytes() 会根据 coder 类型决定占用字节数:
      • Latin-1:1 字符 = 1 字节。
      • UTF-16:1 字符 = 2 字节。

总结:JDK 17+ 扩容机制的核心特点

特性详情
存储结构byte[] + coder(Latin-1/UTF-16),节省ASCII字符串50%内存
扩容公式新容量 = 旧容量 × 2 + 2,确保最小需求
线程安全StringBuffer同步所有方法,StringBuilder非线程安全
边界处理最大容量为Integer.MAX_VALUE - 8,超量则抛OutOfMemoryError

六、StringBuffer/StringBuilder 常用方法

两者方法基本相同,区别在于StringBuffer线程安全(方法有synchronized修饰),StringBuilder非线程安全。

1. 追加与插入

StringBuilder sb = new StringBuilder("Hello");// 追加
sb.append(" World");  // "Hello World"
sb.append(123);       // "Hello World123"// 插入
sb.insert(5, ",");    // "Hello, World123"

2. 删除与替换

StringBuilder sb = new StringBuilder("HelloWorld");// 删除
sb.delete(5, 10);     // "Hello"
sb.deleteCharAt(4);   // "Hell"// 替换
sb.replace(0, 2, "Hi");  // "Hill"

3. 反转与容量管理

StringBuilder sb = new StringBuilder("Hello");// 反转
sb.reverse();         // "olleH"// 容量管理
int capacity = sb.capacity();  // 默认16,动态扩容
sb.ensureCapacity(100);         // 确保容量至少为100

4. 转换为String

StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString();  // "Hello"

七、三者对比表

方法 / 场景String(不可变)StringBuffer(线程安全)StringBuilder(非线程安全)
拼接性能低(每次创建新对象)中(同步开销)高(无同步)
追加操作s = s + “a”(效率低)sb.append(“a”)sb.append(“a”)
插入操作无直接方法sb.insert(0, “a”)sb.insert(0, “a”)
删除操作无直接方法sb.delete(0, 1)sb.delete(0, 1)
反转字符串无直接方法sb.reverse()sb.reverse()
线程安全是(不可变)是(所有方法同步)
适用场景少量拼接、常量字符串多线程频繁操作单线程频繁操作

八、终极使用策略

1.String​​:

字符串常量(如配置信息)
不需要修改的字符串
作为HashMap的键(不可变性保证哈希值稳定)

之所以设计String,且设计为不可变
安全性:作为网络连接参数、类加载名称时不会被篡改
哈希缓存:String常用作HashMap的键,不可变保证hashCode稳定
线程安全:天然线程安全

2.StringBuilder​​:

SQL拼接、JSON构建、日志组装等​​单线程​​场景
示例:

StringBuilder sql = new StringBuilder(128);
sql.append("SELECT * FROM users").append(" WHERE age > ").append(age);

3.StringBuffer​​:

多线程日志处理
全局共享的字符串缓冲区
注意:即使使用StringBuffer,复合操作仍需额外同步

使用场景建议

单线程环境:优先使用 StringBuilder,避免不必要的同步开销。
多线程环境:若需线程安全,使用 StringBuffer 或通过 Collections.synchronizedList 包装 StringBuilder。
高并发场景:考虑使用 StringBuilder 配合手动同步(如 ReentrantLock),或分段处理后合并结果。

一句话记忆口诀

​​“一静(String)两动(Builder/Buffer),单(线程)快多(线程)稳”​​
静:String不可变
动:Builder/Buffer可变
单快:单线程用Builder
多稳:多线程用Buffer

http://www.xdnf.cn/news/396289.html

相关文章:

  • 不换设备秒通信,PROFINET转Ethercat网关混合生产线集成配置详解
  • iVX:图形化编程与组件化的强强联合
  • CSS 盒子模型与元素定位
  • 汽车诊断简介
  • 【Linux高级全栈开发】2.1高性能网络-网络编程——2.1.1 网络IO与IO多路复用——select/poll/epoll
  • 1、虚拟人物角色聊天 AI Agent 设计方案
  • FME处理未知或动态结构教程
  • FPGA生成随机数的方法
  • 2505d,d的一些疑问
  • all-in-one方式安装kubersphere时报端口连接失败
  • C++.变量与数据类型
  • 单片机调用printf概率性跑飞解决方法
  • Go语言实现分布式锁:从原理到实践的全面指南
  • 网络编程(一)网络编程入门
  • LLMs之Mistral Medium 3:Mistral Medium 3的简介、安装和使用方法、案例应用之详细攻略
  • 使用 Java 反射打印和操作类信息
  • Typora输入文字卡顿的问题(原因过长上万字)
  • Spyglass:默认配置文件
  • VMware安装CentOS Stream10
  • ArtStation APP:全球艺术家的创作与交流平台
  • 九、STM32入门学习之WIFI模块(ESP32C3)
  • 轻量级高性能推理引擎MNN 学习笔记 01.初识MNN
  • 跟我学c++高级篇——模板元编程之十三处理逻辑
  • E+H流量计profibus协议如何转换成profinet协议
  • C语言_函数调用栈的汇编分析
  • 【AI论文】作为评判者的感知代理:评估大型语言模型中的高阶社会认知
  • 二分查找的理解
  • Object类
  • wordpress自学笔记 第三节 独立站产品和类目的三种展示方式
  • RabbitMQ的工作队列模式和路由模式有什么区别?