不是文字的字符串对象不需要 new 关键字?

String objects which are not literal not requiring new keyword?

所以我知道还有其他类似的问题,比如this one and this other one。但他们的回答似乎是因为它们是文字的并且是某些不可变文字常量池的一部分,所以它们将保持可用。这对我来说很有意义,但为什么非文字也能正常工作?在处理字符串时,什么时候必须使用 "new" 关键字。在下面的示例中,我使用字符串来做一些事情,但一切正常,我从不使用 "new" 关键字(更正:我从不将它用于 String 类型对象)。

import java.util.*;

class teststrings{

   public static void main(String[] args){
      Scanner in = new Scanner(System.in);
      String nonew;
      String nonew2;
      String literally= "old";
      literally= "new"; //does the word "old" get garbage collected here?
      nonew = in.nextLine(); //this does not use the new keyword, but it works, why?
      System.out.println("nonew:"+nonew);
      System.out.println("literally:"+literally);
      nonew2 = in.nextLine();
      System.out.println("nonew:"+nonew); //the data is still preserved here
      System.out.println("nonew2:"+nonew2);
      //I didn't use the new keyword at all, but everything worked
      //So, when do I need to use it?
   }

}

字符串在 Java 中被特殊处理。 Java JVM 使用称为字符串池的类似于缓存的实现。

与其他对象不同,当您像这样创建文字字符串时: String mystring = "Hello"; Java 将首先检查字符串 "Hello" 是否已存在于字符串池中。如果没有,它将添加到缓存中,并在再次引用时重复使用。

因此,当您第一次将变量分配给 "Hello" 时,它会添加到池中:

String s1 = "Hello";
String s2 = "Hello";
String s3 = s1;
s1 = "SomethingElse"

在上面的代码中,当 s1 被分配 "Hello" 时,JVM 将看到它没有存储在池中,并且 create/add 它到池中。 对于 s2,您再次引用 "Hello"。 JVM 将在池中看到它并将 s2 分配给存储在池中的相同字符串。 s3 被简单地分配给在 s1 的内存地址处引用的值,或者相​​同的字符串 "Hello"。最后,s1 被重新分配给另一个字符串,该字符串在池中尚不存在,因此被添加。此外,s1 不再指向 "Hello",但它不会被垃圾回收,原因有二。 1:t 正在存储在字符串池中,并且 2: s2 也指向相同的引用字符串。

对于字符串,永远不要使用 new 关键字来创建文字字符串。如果这样做,您就没有利用字符串池重用的优势,并且可能导致同一字符串的多个实例存在于内存中,这是一种浪费。

几点: "Does the word "old“在这里收集垃圾?” 您的编译器很可能意识到它从未被使用过,因此完全跳过它。

Scanner::nextLinereturns一个String,方法返回的值用于赋值

至于什么时候 使用 new Strings...嗯,很少可能是最好的。我唯一一次看到它被用于内部常量。例如

public class MatchChecker {
    private static final String ANY_VALUE = new String("*");

    private final Map<Object, String> map = new HashMap<Object, String>();

    public void addMatch(Object object, String string) {
        map.put(object, string);
    }

    public void addAnyValueMatch(Object object) {
        map.put(object, ANY_VALUE);
    }

    public boolean matches(Object object, String string) {
        if (!map.contains(object)) {
            return false;
        }
        if (map.get(object) == ANY_VALUE || map.get(object).equals(string)) {
            return true;
        }
        return false;
    }
}

这意味着 只有 通过 addAnyValueMatch 添加的对象会匹配任何值(因为它是用 == 测试的),即使用户使用 "*" 作为 addMatch.

中的字符串