-2

可以通过两种方式初始化字符串:

String s="ABCD";

或者

String s=new String("ABCD");

这两个是相同的还是不同的??我再次注意到

String s="ABCD";
String z="ABCD";
boolean b=s.equals(z);

结果为真,但

String s=new String("ABCD");
String z=new String("ABCD");
boolean b=s.equals(z);

结果为假。谁能解释一下为什么会这样??

4

6 回答 6

10

你所有的例子都必须有结果true,即使是第二个

为什么?该类String有一个重写的equals方法来检查两个字符串是否相同 - 以逐个字符为基础。另一方面,运算符 == 检查两个字符串引用是否指向同一个对象。

因此,例如:

String a = new String("asd"); //new object, will add to pool though
String b = new String("asd"); //new object
String c = "asd"; //will use the pool
boolean b1 = (a == b); //false, different objects (same contents though)
boolean b2 = (a.equals(b)); //true, same contents
boolean b3 = (a == c); //false, different objects
boolean b3 = (a.equals(c)); //true, same contents

还有一点需要注意的是 Java 池化字符串。如果您在代码中的某处使用字符串文字,JVM 将汇集该值,当您再次使用它时,在代码中的其他地方,JVM 将检测到它并指向您对它的引用。字符串是不可变的,所以这是非常安全的。

我要强调的最后一件事是构造String b = new String("asd");。在这种情况下,将创建一个新的 String 对象(因为 operator new)。即使“asd”已经存在于字符串池中,字符串b也会指向一个单独的内存位置,并带有一个新对象。

如果池中不存在“asd”,那么不仅会b指向非池化区域,还会将“asd”添加到池中,以防万一(以备将来参考)。

于 2012-09-22T06:16:45.543 回答
0

建议大家阅读和分析String.class的源码,尤其是equals和intern方法,另外还要研究一下java的内存结构。

字符串#等于

/**
 * Compares this string to the specified object.  The result is {@code
 * true} if and only if the argument is not {@code null} and is a {@code
 * String} object that represents the same sequence of characters as this
 * object.
 *
 * @param  anObject
 *         The object to compare this {@code String} against
 *
 * @return  {@code true} if the given object represents a {@code String}
 *          equivalent to this string, {@code false} otherwise
 *
 * @see  #compareTo(String)
 * @see  #equalsIgnoreCase(String)
 */
public boolean equals(Object anObject) {
if (this == anObject) {
    return true;
}
if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = count;
    if (n == anotherString.count) {
    char v1[] = value;
    char v2[] = anotherString.value;
    int i = offset;
    int j = anotherString.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
        return false;
    }
    return true;
    }
}
return false;
}

字符串#intern

/**
 * Returns a canonical representation for the string object.
 * <p>
 * A pool of strings, initially empty, is maintained privately by the
 * class <code>String</code>.
 * <p>
 * When the intern method is invoked, if the pool already contains a
 * string equal to this <code>String</code> object as determined by
 * the {@link #equals(Object)} method, then the string from the pool is
 * returned. Otherwise, this <code>String</code> object is added to the
 * pool and a reference to this <code>String</code> object is returned.
 * <p>
 * It follows that for any two strings <code>s</code> and <code>t</code>,
 * <code>s.intern()&nbsp;==&nbsp;t.intern()</code> is <code>true</code>
 * if and only if <code>s.equals(t)</code> is <code>true</code>.
 * <p>
 * All literal strings and string-valued constant expressions are
 * interned. String literals are defined in &sect;3.10.5 of the
 * <a href="http://java.sun.com/docs/books/jls/html/">Java Language
 * Specification</a>
 *
 * @return  a string that has the same contents as this string, but is
 *          guaranteed to be from a pool of unique strings.
 */
public native String intern();

内存结构

http://www.yourkit.com/docs/kb/sizes.jsp

于 2012-09-22T06:48:31.043 回答
0

对不起,但我认为。

String s=new String("ABCD");
String z=new String("ABCD");
boolean b=s.equals(z);

它应该是返回真请再次检查..!!

您的问题在不同方面是正确的(使用 == 运算符)有两种方法可以在 Java 中创建 String 对象:

  • 使用 new 运算符。例如,

    String str = new String("Hello");

  • 使用字符串文字或常量表达式)。例如,

    String str="Hello"; (string literal) or
    String str="Hel" + "lo"; (string constant expression).

字符串字面
量字符串分配,就像所有的对象分配一样,在时间和内存上都被证明是昂贵的。JVM 在实例化字符串文字时会执行一些技巧以提高性能并减少内存开销。为了减少在 JVM 中创建的 String 对象的数量,String 类保留了一个字符串池。每次您的代码创建字符串文字时,JVM 首先检查字符串文字池。如果该字符串已存在于池中,则返回对池实例的引用。如果池中不存在字符串,则实例化一个新的 String 对象,然后将其放入池中。Java 可以进行这种优化,因为字符串是不可变的,并且可以共享而不必担心数据损坏。

所以从你的问题

String s="ABCD";
String z="ABCD";
boolean b=s==z; 

我应该返回true,因为两个对象具有相同的引用。

但万一

String s=new String("ABCD");
String z=new String("ABCD");
boolean b = s==z;

它将返回false,因为两个对象不同

于 2012-09-22T06:25:12.680 回答
-1

当我们调用以下语句时

String s="ABCD";
String z="ABCD";

然后它将在字符串池中检查,如果池中已经存在,则将地址引用到变量。
但是当我们调用new关键字然后明确表示要创建新内存时。

于 2012-09-22T06:12:08.767 回答
-3

我对此不确定,但我在第二个例子中猜测

String s=new String("ABCD");
String z=new String("ABCD");

它像对象一样声明,因此当您尝试检查相等性时,肯定会给您false(对象不能等于对象)

于 2012-09-22T06:14:10.037 回答
-4
String s="ABCD";
String z="ABCD";

引用内存池中的相同字符串。然而

String s=new String("ABCD");
String z=new String("ABCD");

为字符串生成单独的内存空间。所以输出是这样的。这也回答了你的第一个问题。

于 2012-09-22T06:08:10.030 回答