## 认知
两者都是[[不可变的]]字符序列。任何看起来修改字符串的操作实际上都是创建并返回一个**新**的字符串对象。
在 java 中 String 类为什么要设计成 final?- 胖君的回答 - 知乎
https://www.zhihu.com/question/31345592/answer/114126087
Strings are [immutable](不可变的.md) sequences of Unicode code points -- individual "characters" or code points (strings of length 1)
## [CheatSheet](CheatSheet.md)
好的,在您提供的表格基础上,补充“字符串转数字”和“字符串转布尔”这两项:
| | | | |
| ----------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **目的 (Purpose)** | **Python (str) 最简方式** | **Java (String) 最简方式** | **备注 (Remarks)** |
| 获取长度 | `len(my_str)` | `myString.length()` | Python 内置函数 vs Java 方法。|
| 字符串拼接 | `str1 + str2` / f-string / `.join()` | `str1 + str2` / `StringBuilder` / `StringBuffer` | 两者都可用 `+`。Java 中循环内用 `+` 可能效率低 (创建过多对象),推荐 `StringBuilder`。Python `+` 通常优化较好。|
| 访问字符 (按索引) | `my_str[index]` | `myString.charAt(index)` | Python 用下标返回单字符字符串;Java 用方法返回 `char` 原始类型。|
| 获取子串 / 切片 | `my_str[start:stop:step]` | `myString.substring(beginIndex, endIndex)` | Python 切片更灵活 (步长/负索引);Java `substring` 结束索引不包含在内。都返回新字符串。|
| 检查子串是否存在 | `substring in my_str` | `myString.contains(substring)` | Python 用 `in` 操作符;Java 用方法。|
| 查找子串索引 | `my_str.find(sub)` / `.index(sub)` | `myString.indexOf(sub)` | Python `find` 未找到返回-1, `index` 抛异常;Java `indexOf` 未找到返回-1。都查找首次出现。|
| 替换子串 | `my_str.replace(old, new,[count])` | `.replace(old, new)` / `.replaceAll(regex, new)` | 两者都有字面量替换。Java 区分字面量替换 (`replace`) 和正则替换 (`replaceAll`)。Python `replace` 可选替换次数。都返回新字符串。|
| 分割字符串 | `my_str.split(sep=None)` | `myString.split(regex)` | Python `split()` 默认按空白分割;Java `split()` **默认使用正则表达式**作为分隔符,需注意转义。都返回列表/数组。|
| 连接序列为字符串 | `separator.join(iterable)` | `String.join(separator, iterable)` (Java 8+) | 句法相反(分隔符对象 vs 静态方法)。Java 8+ 后方便很多,旧版需手动 `StringBuilder`。|
| 大小写转换 | `.lower()`, `.upper()`, `.title()`... | `.toLowerCase()`, `.toUpperCase()` | 两者都有基础大小写转换。Python 提供更多内置选项。都返回新字符串。|
| 去除首尾空白 | `.strip()`, `.lstrip()`, `.rstrip()` | `.trim()` / `.strip()` (Java 11+) | Python 控制更细致。Java `.trim()` 历史悠久但行为与 Python 不同 (<= U+0020);Java 11+ 的 `.strip()` 更符合 Unicode 空白定义,并提供 `stripLeading/Trailing`。|
| 检查前缀/后缀 | `.startswith(prefix)`, `.endswith(suffix)` | `.startsWith(prefix)`, `.endsWith(suffix)` | 方法名和功能非常相似。|
| | | | |
| **字符串转数字** | **`int(str)`**, **`float(str)`** | **`Integer.parseInt(str)`**, **`Float.parseFloat(str)`**, **`Double.parseDouble(str)`** | Python 用内置函数,Java 用包装类的静态方法。格式错误时都抛出异常 (Python: `ValueError`, Java: `NumberFormatException`)。|
| **字符串转布尔** | **`bool(str)`** (判空) / **`str.lower() == 'true'`** (语义) | **`Boolean.parseBoolean(str)`** | Python `bool()` 仅检查是否为空串 (非空即 `True`);Java `parseBoolean` 明确检查是否为 (不区分大小写) "true",否则结果为 `false`。语义转换 Python 需手动比较。|
| **不可变性 (Immutability)** | **是** | **是** | **核心特性**:对象一旦创建,其内容(字符序列)不能被更改。所有修改操作都返回新的 String/str 对象。|
| | | | |
| | | | |
## python 中的 string
```Python
def remove_suffix_ness(word):
# ... docstring ...
new_word = word[:-4] # 移除 'ness',对于 "heaviness",new_word 是 "heavi"
if new_word[-1] == 'i': # 检查最后一个字符是否是 'i',这里是 True
# 尝试将最后一个字符 'i' 替换为 'y'
new_word[-1] = 'y' # <--- 问题在这里!
return new_word # 返回 new_word
```
- **错误原因:** Python 中的**字符串 (string) 是不可变的 (immutable)**。这意味着你**不能**直接修改字符串中的某个字符。语句 `new_word[-1]= 'y'` 试图修改字符串,这是不允许的,它实际上不会产生任何效果(或者在某些情况下会直接报错 `TypeError`)。因此,即使 `if` 条件满足,`new_word` 仍然是 `"heavi"`,函数最后返回的就是 `"heavi"`。
## java 中的 string
下面这个 n 次的循环,时间复杂度其实是 n 方
```java
public String statement() {
String result = "";
for (int i = 0; i < numItems(); i++)
result += lineForItem(i); // String concatenation
return result;
}
```
1. Java中的字符串是不可变的(immutable)。
2. 每次使用+操作符拼接字符串时,实际上会创建一个新的字符串对象。
步骤如下:
1. S1 + S2: 需要挪动长度为m的S1和长度为m的S2,总共2m个字符。
2. (S1 + S2) + S3: 需要挪动长度为2m的(S1 + S2)和长度为m的S3,总共3m个字符。
3. ((S1 + S2) + S3) + S4: 需要挪动长度为3m的((S1 + S2) + S3)和长度为m的S4,总共4m个字符。... n. 最后一步需要复制长度为(n-1)m的中间结果和长度为m的Sn,总共nm个字符。
$
\sum_{i=1}^{n} im = m\sum_{i=1}^{n} i
$
把 n 次做 sum,那么求和之后就是
$
m\sum_{i=1}^{n} i = m \cdot \frac{n(n+1)}{2} \approx \frac{mn^2}{2}
$
>[!最佳实践]
> 所以不要在 for 循环中用`+`来连接字符串
- StringBuffer线程安全,但是性能较低
- StringBuilder线程不安全,但是只有多个线程共用一个实例时才会产生
- 就像 HashTable 也是线程安全但是我们一般不用一样,因为性能低
```java
public class StringBuilderThreadUnsafeDemo {
public static void main(String[] args) throws InterruptedException {
StringBuilder sharedStringBuilder = new StringBuilder();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
sharedStringBuilder.append("a");
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("StringBuilder长度: " + sharedStringBuilder.length());
System.out.println("预期长度: 2000");
}
}```