如何解决使用“+”运算符的Java字符串连接
当我们使用 {{ 将大小为 S2
的字符串 Y
连接到大小为 S1
的字符串 X
(已经存在于堆中)时,实际会发生什么1}} 运算符?
这是我的想法:
如果我执行以下函数:
+
如果字符串池(存储在堆中)中存在 class StringConcatenation{
String S1;
String concat(String S2){
this.S1 = this.S1 + S2;
}
}
并且我们执行 concat 方法,那么该方法将在堆栈上执行。
因此,CPU 将需要复制堆栈中的 S1
=> READ S1
由于字符串是不可变的,Java 必须创建一个新对象(让我们将其引用命名为 S1
)。
现在,S1 和 S2 的内容被复制到新对象 => COPY S3
+ COPY S1
然后引用 S1 指向新对象。
因此,总时间复杂度为 O(READ S2
+ COPY S1
+ COPY S1
) = {{ 1}} = S2
。
我的思维过程正确吗?
解决方法
在 doc 中,您可以阅读:
Java 语言为字符串连接运算符 ( + ) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。
a = a + b is the equivalent of a += b or:
a = new StringBuilder()
.append(a)
.append(b)
.toString();
,
免责声明: String
类已经进行了多次更改以提高性能和空间利用率。当 JIT 编译代码时会发生什么是完全未定义的。以下是一个简化,并忽略了可能应用或可能不应用的任何优化。
String
是一个封装了 char[]
的类。数组长度始终正好是字符串的 length()
。类和底层数组是不可变的。
class String {
private final char[] arr;
}
StringBuilder
(和StringBuffer
)是另一个封装了char[]
的类,但数组几乎总是大于数组中的字符数。类和数组都是可变的。
class StringBuilder {
private char[] arr;
private int len;
}
当您使用 +
运算符进行字符串连接时,编译器将其生成为:
// Java code
s = s1 + s2 + s3;
// Generated code
s = new StringBuilder().append(s1).append(s2).append(s3).toString();
StringBuilder
最初将创建长度为 16 的数组,并在需要时重新分配数组。最坏的情况是 s1
、s2
和 s3
对于当前数组来说都太大了,因此每次 append()
调用都需要重新调整数组大小。
这意味着将按以下方式进行:
-
new StringBuilder()
- 创建char[16]
。 -
append(s1)
- 调整arr
的大小,然后将字符从s1.arr
复制到数组。 append(s2)
- 调整arr
的大小,将现有内容(来自s1
的字符)复制到新数组,然后将字符从s2.arr
复制到数组。>-
append(s3)
- 调整arr
的大小,将现有内容(来自s1
和s2
的字符)复制到新数组,然后从s3.arr
复制字符到数组。 -
toString()
- 创建新的String
,其中char[]
的大小正好适合StringBuilder
中的字符,然后复制内容(来自 {{1} }、s1
和s2
) 到新的s3
。
来自 String
的所有字符最终被复制了 4 次。
如果字符串连接是s1
,就像问题中一样,那么S1 + S2
中的字符被复制2或3次,S1
中的字符被复制2次。
因为时间复杂度通常是最坏的情况,这意味着O(3m + 2n),而不是建议的O(2m + n)在问题中。当然,Big-O消除了常数因子,所以实际上是O(m + n)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。