我知道有两种方法可以在Java中创建String:
String a = "aaa";
String b = new String("bbb");
首先,Java肯定会在字符串池中创建一个String对象,并使a
引用它。 (假设“aaa”之前不在游泳池里。)
使用第二种方法,将在堆中创建一个对象,但是jvm还会在字符串池中创建一个对象吗?
在这篇文章Questions about Java's String pool中,@ Jesper说:
如果你这样做:
String s = new String("abc");
然后池中将有一个String对象,代表文字“abc”,>并且将有一个单独的String对象,而不是在池中,它包含>的副本。合并对象的内容。
如果这是真的,那么每次使用new String("bbb");
时,在池中创建一个对象“bbb”,这意味着通过上面的任何一种方式,java将始终在池中创建一个字符串对象。那么intern()
用于什么?在文档http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern()中,它说:
当调用intern方法时,如果池已经包含一个等于此String对象的字符串(由equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。
这意味着有些字符串不在池中,可能吗?哪一个是真的?
答案 0 :(得分:9)
如您所知,Java编程语言中的不可变对象中的String
,这意味着一旦构造就无法更改。因此,JVM能够维护文字池,这有助于减少内存使用并提高性能。每次使用String
文字时,JVM都会检查文字池,如果文字已经可用,则会返回相同的引用。如果不是,则会在文字池中创建并添加新的String对象。
当您尝试创建类似基元或文字/常量的String
时,会应用此理论。
String str = "bbb";
但是当你创建一个新的String对象
时String str = new String("bbb");
重写上述规则并始终创建新实例。
但即使您使用intern
创建String
,String
类中的literal
API也可用于从String
池中选择new
引用str3
运营商。请查看以下给出的示例。尽管new
是使用intern
运算符创建的,因为我们使用了literal
方法,JVM从public class StringInternExample {
public static void main(final String args[]) {
final String str = "bbb";
final String str1 = "bbb";
final String str2 = new String("bbb");
final String str3 = new String("bbb").intern();
System.out.println("str == str1 : "+(str == str1));
System.out.println("str == str2 : "+(str == str2));
System.out.println("str == str3 : "+(str == str3));
}
}
池中获取了引用。
str == str1 : true
str == str2 : false
str == str3 : true
输出上述代码:
{{1}}
您可以查看:Confusion on string immutability
答案来源:http://ourownjava.com/java/java-string-immutability-and-intern-method/
Shishir
答案 1 :(得分:4)
我们的String
对象基本上可以通过两种方式进入池中:
"bbb"
等源代码中使用文字。intern
。 intern
适用于有String
的情况,而不是来自池中的String bb = "bbb".substring(1); // substring creates a new object
System.out.println(bb == "bb"); // false
System.out.println(bb.intern() == "bb"); // true
。例如:
System.out.println(new String("bbb").intern() == "bbb"); // true
或略有不同:
new String("bbb")
String fromLiteral = "bbb"; // in pool
String fromNewString = new String(fromLiteral); // not in pool
会创建两个对象......
String
......但它更像是一个特例。它创建了两个对象,因为"bbb"
refers to an object:
字符串文字是对类
String
[...]的实例的引用。此外,字符串文字始终引用类
new String(...)
的相同实例。
而String
会创建一份副本。
但是,有许多方法可以在不使用文字的情况下创建String
个对象,例如:
substring
方法。 (split
,replace
,String
等。)Scanner
,例如Reader
或intern
。 String
允许您将它们添加到池中或检索现有对象(如果有)。在大多数情况下,实习==
是不必要的,但它可以用作优化,因为:
答案 2 :(得分:1)
是的,new String("abc")
将在内存中创建一个新对象,因此建议避免使用它。请查看Josh Bloch的Effective Java第5项“避免创建不必要的对象”,其中有更好的解释:
作为不做的极端例子,请考虑以下陈述:
String s = new String("stringette"); // DON'T DO THIS!
声明 每次执行时都会创建一个新的String实例,而不是 那些对象创作是必要的。 String的参数 构造函数(“stringette”)本身就是一个String实例,在功能上 与构造函数创建的所有对象相同。如果这 用法发生在循环或频繁调用的方法中,数百万 可以不必要地创建字符串实例。改进版是 只需以下内容:
String s = "stringette";
此版本使用了 单个String实例,而不是每次创建一个新实例 执行。此外,保证对象将被重用 通过在同一个虚拟机中运行的任何其他代码 包含相同的字符串文字[JLS,3.10.5]。
http://uet.vnu.edu.vn/~chauttm/e-books/java/Effective.Java.2nd.Edition.May.2008.3000th.Release.pdf
答案 3 :(得分:1)
使用第二种方法,将在堆中创建一个对象,但是jvm还会在字符串池中创建一个对象吗?
是的,但是字符串文字 "bbb"
,它确保了实习字符串 1 。字符串构造函数创建一个 new 字符串对象,该对象是具有相同长度和内容的副本 - 新创建的字符串不自动实现。
如果这是真的,那么每次使用新的String(“bbb”);时,在池中创建一个对象“bbb”,这意味着通过上面的任何一种方式,java将始终在池中创建一个字符串对象。那么intern()用于什么?
仅自动实习字符串文字。必须手动实现其他字符串对象,如果这是期望的行为。
这意味着有些字符串不在池中,可能吗?
除了对String.intern
的手动调用外,仅字符串文字会产生实习字符串。
虽然我建议在这种情况下使用专门的集合,但在可以用于avoid creating extra duplicate objects的情况下,实习可能很有用。实习可能有用的一些用例 - 例如,相同的字符串值可以出现多次 - 是在JSON密钥和XML元素/属性名称中。
1 这是微不足道的原因,请考虑:
String _b = "bbb"; // string from string literal (this is interned)
String b = new String(_b); // create a NEW string via "copy constructor"
b == _b // -> false (new did NOT return an interned string)
b.equals(_b) // -> true (but it did return an equivalent string)
b.intern() == _b // -> true (which interns to .. the same string object)