字符串是Java中的对象,那么为什么我们不使用“new”来创建它们呢?

时间:2010-01-05 21:30:44

标签: java string core new-operator

我们通常使用new关键字创建对象,例如:

Object obj = new Object();

字符串是对象,但我们不使用new来创建它们:

String str = "Hello World";

这是为什么?我可以使用new制作字符串吗?

15 个答案:

答案 0 :(得分:123)

除了已经说过的内容之外,Java中的字符串文字 [即,类似"abcd"但不像new String("abcd")的字符串]被实习 - 这意味着每次你参考“abcd”,您将获得对单个String实例的引用,而不是每次都引用一个新实例。所以你将拥有:

String a = "abcd";
String b = "abcd";

a == b; //True

但如果你有

String a = new String("abcd");
String b = new String("abcd");

那么就有可能

a == b; // False

(如果有人需要提醒,请始终使用.equals()来比较字符串; ==测试物理相等性。)

实习字符串文字很好,因为它们经常被使用多次。例如,考虑(设计的)代码:

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

如果我们没有字符串的实习,“下一次迭代”需要实例化10次,而现在它只会被实例化一次。

答案 1 :(得分:30)

字符串是Java中的“特殊”对象。 Java设计人员明智地决定使用Strings,以至于他们需要自己的语法和缓存策略。当你通过说:

声明一个字符串时
String myString = "something";

myString是对String对象的引用,其值为“something”。如果您稍后声明:

String myOtherString = "something";

Java非常聪明,可以确定myString和myOtherString是相同的,并将它们作为同一个对象存储在全局String表中。它依赖于您无法修改字符串来执行此操作的事实。这样可以降低所需的内存量,并可以更快地进行比较。

相反,如果你写了

String myOtherString = new String("something");

Java将为您创建一个全新的对象,与myString对象不同。

答案 2 :(得分:14)

String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

希望这清除了一些疑虑。 :)

答案 3 :(得分:6)

这是捷径。最初并不是这样,但Java改变了它。

FAQ简要介绍了这一点。 Java规范指南也讨论了它。但我无法在网上找到它。

答案 4 :(得分:6)

字符串需要进行一些优化(因为缺少更好的短语)。请注意,String也有运算符重载(对于+运算符) - 与其他对象不同。所以这是一个特例。

答案 5 :(得分:4)

我们通常使用String文字以避免创建不必要的对象。如果我们使用new运算符创建String对象,那么它将每次都创建新对象。

示例:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

对于内存中的上述代码:

enter image description here

答案 6 :(得分:2)

在Java中,字符串是一种特殊情况,其中许多规则仅适用于字符串。双引号使编译器创建一个String对象。由于String对象是不可变的,因此这允许编译器实现多个字符串,并构建一个更大的字符串池。两个相同的String常量将始终具有相同的对象引用。如果您不希望出现这种情况,那么您可以使用新的String(“”),这将在运行时创建一个String对象。 intern()方法过去很常见,可以根据字符串查找表检查动态创建的字符串。在interned中的字符串后,对象引用将指向规范的String实例。

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

当类加载器加载一个类时,所有String常量都被添加到String池中。

答案 7 :(得分:0)

随意使用

创建一个新字符串
String s = new String("I'm a new String");

通常的符号s = "new String";或多或少是一种方便的快捷方式 - 应该用于性能原因,除非那些非常罕见的情况,你真的需要符合等式的字符串

(string1.equals(string2)) && !(string1 == string2)

修改

回应评论:这是旨在提出建议,但只是对提问者论文的直接回应,我们不使用'new'关键字< / em> for Strings,这根本不是真的。希望这个编辑(包括上面的内容)澄清一点。顺便说一下 - 关于上述问题,有几个好的,更好的答案。

答案 8 :(得分:0)

句法糖。在

String s = new String("ABC");

语法仍然可用。

答案 9 :(得分:0)

你仍然可以使用new String("string"),但是创建没有字符串文字的新字符串会更难...你必须使用字符数组或字节:-)字符串文字有一个额外的属性:所有相同的字符串来自任何类的文字都指向相同的字符串实例(它们是实体)。

答案 10 :(得分:0)

几乎不需要新的字符串,因为文字(引号中的字符)已经是加载主机类时创建的String对象。在文字和don上调用方法是完全合法的,主要区别在于文字提供的便利。如果我们必须创建一个字符数组并用char填充char并且它们执行一个新的String(char数组),那将是一个主要的痛苦和浪费。

答案 11 :(得分:0)

文字池包含在不使用关键字new的情况下创建的任何字符串。

有一点不同:没有新引用的字符串存储在String文字池中,而带有new的字符串表示它们存在于堆内存中。

带有new的字符串在内存中的其他地方就像任何其他对象一样。

答案 12 :(得分:0)

因为String是java中的不可变类。

现在为什么它是不可变的? 因为String是不可变的所以它可以在多个线程之间共享,我们不需要在外部同步String操作。 由于String也用于类加载机制。因此,如果String是可变的,则java.io.writer可能已更改为abc.xyz.mywriter

答案 13 :(得分:0)

TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

输出:

  

我创建了两个单独的对象,都有一个字段(ref)'Name'。所以,即使在这种情况下,“Jan Peter”也是共享的,如果我理解java的处理方式..

答案 14 :(得分:0)

StringPool是使用Java中的Hashmap实现的。如果我们始终使用新的关键字创建它,则它不在字符串池中搜索并为其创建新的内存,如果我们正在运行内存密集型操作并且如果要使用会影响性能的所有关键字创建所有字符串,则稍后可能需要我们的应用程序。因此,建议不要使用新的关键字来创建字符串,因为只有这样,它才会进入字符串池,而后者又是一个Hashmap,(保存了内存,假设我们有很多用new关键字创建的字符串)将在此处存储和如果字符串已经存在,则该字符串的引用(通常位于堆栈内存中)将返回到新创建的字符串。 因此,它可以提高性能。