在Java中重复更新字符串

在Java中重复更新字符串,java,Java,所以我知道Java中的字符串是不可变的。我对如何重复更新某个字符串感兴趣 例: publicstaticvoidmain(字符串[]args){ String myString=“嘿”; 对于(inti=1;i,您的代码工作得非常好。尽管不建议像您那样处理字符串。 看看Java的StringBuilder: 在StringBuilder的帮助下,可以修改字符串 this won't work in Java because I've already declared and assigned m

所以我知道Java中的字符串是不可变的。我对如何重复更新某个字符串感兴趣

例:

publicstaticvoidmain(字符串[]args){
String myString=“嘿”;

对于(inti=1;i,您的代码工作得非常好。尽管不建议像您那样处理字符串。 看看Java的StringBuilder:

在StringBuilder的帮助下,可以修改字符串

this won't work in Java because I've already declared and assigned myString
如果您错了,它仍然可以工作,但每次添加到字符串时,它都会生成一个新字符串

如果在追加/添加字符串时不想生成新字符串,则
StringBuilder
是解决方案

示例:

public static void main(String args[]) {


     StringBuilder sb = new StringBuilder("hey");
        for (int i = 1; i <= 9; i++) {
            sb.append("hey");
        }

}
publicstaticvoidmain(字符串参数[]){
StringBuilder sb=新StringBuilder(“嘿”);
对于(int i=1;我可以快速回答
您应该使用
StringBuilder
来实现这类功能。它的设计目的是将字符串组合在一起,而无需不断复制或保留旧字符串

public class SimpleGrowingString {
    private StringBuilder stringBuilder;

    public SimpleGrowingString() {
        this.stringBuilder = new Stringbuilder();
    }

    public void addToString(String str) {
        this.stringBuilder.append(str);
    }

    public String getString() {
        return this.stringBuilder.toString();
    }
}

一个不那么快的回答: 不变的 当字符串不可变时,您可以重新分配字符串变量。
然后,变量将引用(指向)分配给它的新字符串,旧值将标记为
垃圾回收
,并且只在RAM中挂起,直到垃圾回收器离开它的屁股并四处清除它。也就是说,只要没有其他引用它(或它的子部分)还在某个地方

不可变意味着不能更改字符串本身,而不是不能重新指定现在指向其值的变量


例如

字符串
“字符串一”
存在于内存中,无法更改、修改、剪切、添加等。
它是不变的

如果我说:

str = "a different string";
然后变量
str
现在引用内存中的另一段数据;字符串
“另一个字符串”

原始字符串
“String one”
仍然是与我们刚刚告诉句柄它指向其他内容之前完全相同的字符串。旧字符串仍然在内存中浮动,但现在它是无头的,我们不再有任何方法实际访问该值。
这就引出了垃圾收集的概念


垃圾,到处都是垃圾。 垃圾收集器时不时地运行,并清除不再使用的旧的、不必要的数据。
它通过检查当前是否有任何有效的句柄/变量指向数据来决定什么是有用的,什么是无用的。如果没有任何东西在使用它,我们甚至无法再访问它,它对我们来说是无用的,它会被转储

但你永远都不能真正依靠垃圾收集器按时、快速地清理垃圾,甚至不能让它在你想要的时候运行。它在自己的时间里做自己的事情。你最好尽量减少它的工作量,而不是假设它会在你之后一直清理

现在,您已经有了一个公认的非常基本的垃圾收集基础,我们可以讨论为什么不将字符串添加到一起:


字符串con+cat+en+a+tion 对字符串使用
+
的一个大问题(以及设计
StringBuilder
StringBuffer
的原因)它创建了大量字符串。到处都是字符串!它们可能会很快成为垃圾收集的候选对象,这取决于您的使用情况,但如果处理不当,它们仍然会导致膨胀,特别是当涉及循环时,因为垃圾收集器会在感觉非常好的时候运行,而我们无法真正做到这一点控制我们不能说事情没有失控,除非我们自己阻止事情失控

执行以下内容的简单字符串串联:

"a String" + " another String"
实际上会导致内存中有三个字符串:

"a String", " another String" and "a String another String"
0:
  "a chunk of RAM "

1:
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM"

2:
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM"
  "a chunk of RAM a chunk of RAM a chunk of RAM"

3: 
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "

4:
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM"

5:
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM"
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "

6:
  "a chunk of RAM "
  "a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM"
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "
  "a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM a chunk of RAM "
将其扩展为一个简单、相当短的循环,您可以看到事情如何很快失控:

String str = "";
for (int i=0; i<=6; i++) {
    str += "a chunk of RAM ";
}
等等等等…你可以看到它的发展方向和速度


故事的寓意 如果要循环和组合字符串,请使用
StringBuilder
StringBuffer
这就是它们的用途


“旁注”。子串(4); 由于字符串的不变性,连接字符串并不是导致大量内存浪费的唯一方法

正如我们不能在绳子的末端加上东西一样,我们也不能剪掉尾巴

String moderatelyLongString = "a somewhat lengthy String that rambles on and on about nothing in particular for quite a while even though nobody's listening";
如果我们只想使用这个字符串的一部分,我们可以使用
String.substring()
方法:

String snippedString = moderatelyLongString.substring(0, 13);
System.out.println(snippedString):

>> a somewhat le
好吧,那有什么问题吗?
好吧,如果我们想转储第一个长字符串,但保留短字符串,你可能会认为我们可以说:

moderatelyLongString = null;
你可能会认为这会让这根长长的绳子被遗弃,独自一人,在角落里哭泣,等待GC的到来,把它踢到寒冷中,但你错了

由于我们在
snippedString
中仍然保留了两个较长链的字符,因此整个
中等长度的字符串都停留在堆上,浪费空间

如果你想这样做,但摆脱了无用的重量,你会想做的是复制缩短的部分,但不保留一个领带到长位:

String aNicerMorePoliteShortString = new String(moderatelyLongString.substring(0, 13));
这将复制从长字符串中提取的短字符串,长字符串是它自己的独立字符数组,与长字符串上的纠缠挂钩无关

现在这样做,这一次,将长字符串标记为可供收集,因为我们与它没有剩余的关联:

moderatelyLongString = null;

然而 如果您只是想在每次迭代时在循环中显示一个不同的字符串,那么您要做的就是(重新)使用一个变量,以便尽快释放内存中所有较旧的字符串,并尽快将其用于垃圾收集。声明您的va
moderatelyLongString = null;
String aNicerMorePoliteShortString = new String(moderatelyLongString.substring(0, 13));
moderatelyLongString = null;
String whatYouWantToUse;
for (int i=0; i<100; i++) {
    whatYouWantToUse = someStringyGettyMethod();
    howYouWantToUseIt(whatYouWantToUse);
}
for (int i=0; i<100; i++) {
    howYouWantToUseIt(someStringyGettyMethod());
}
public static void main(String[] args) {
    String myString = "hey";
    for (int i = 1; i <= 9; i++) {
        myString += "hey";
    }
    System.out.println(myString); // prints "heyheyheyheyheyheyheyheyheyhey"
}
public static void main(String[] args) {
    StringBuilder builder = new StringBuilder(50); // estimated length
    for (int i = 1; i <= 9; i++) {
        builder.append("hey");
    }
    String myString = builder.toString();   // convert to String when needed
    System.out.println(myString);           // prints "heyheyheyhey..."
}