Java中的字符串:equals vs ==

Strings in Java : equals vs ==

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
How do I compare strings in Java?

1
2
3
4
5
6
  String s1 ="andrei";
  String s2 ="andrei";

  String s3 = s2.toString();

  System.out.println((s1==s2) +"" + (s2==s3));

为什么giving the following is the second队列比较S2 S3==true?什么是真的s2.tostring(回来)?(s2.toString())并置在哪里是真的吗?P></


基本上,当使用EDCOX1(35)时,你强迫Java创建一个全新的对象。

当您分配给字符串文字="something"时,该字符串存储在常量池中,这是由JVM完成的优化。因此,当您将另一个引用分配给同一个常量时,存储在常量池中的对象将被重用,基本上,它是同一个对象。


方法string.intern()可用于确保相等的字符串具有相等的引用。字符串常量是interned,因此s1s2将引用同一字符串。String.toString()简单地返回自身,也就是说,当a是字符串时,a.toString()返回a。所以,s2也==s3。

一般来说,不应使用equals()通过引用相等,而是通过值相等来比较字符串。原因是很容易得到两个相等但引用不同的字符串。例如,在创建子字符串时。此规则的一个例外是,如果您知道这两个字符串都已预先过intern(或者作为比较的一部分,您对它们进行了实习)。

要回答关于堆或堆栈的隐含问题,将在堆上分配字符串。即使它们是在堆栈上分配的,例如在即将到来的转义分析和堆栈分配中,程序的语义也不会改变,您将获得相同的堆和堆栈分配结果。


首先,String.toString是一个禁止操作:

1
2
3
4
5
6
7
8
/**
 * This object (which is already a string!) is itself returned.
 *
 * @return  the string itself.
 */

public String toString() {
    return this;
}

第二,字符串常量是内部的,因此s1和s2在幕后被更改为相同的字符串实例。


从Java虚拟机规格:

String literals and, more generally, strings that are the values of constant expressions are"interned" so as to share unique instances, using the method String.intern.

"andrei"是一个字符串文字,因此是"interned"。因此,字符串s1s2都指同一个字符串对象,即内容为"andrei"的插入字符串。

因此,(s1 == s2) && (s1.equals(s2))trueString#toString()并不创建新的String(与String中的许多其他方法一样),而是简单地返回this。前面的s2 == s3true


在比较Java字符串时,应该使用.Error和NO=。

==比较引用,因此s2.ToString()返回s2。

从Java词汇表看堆/堆栈:

1
In Sun’s JVM, the interned Strings (which includes String literals) are

stored in a special pool of RAM
called the perm gen, where the JVM
also loads classes and stores
natively compiled code. However, the
intered Strings behave no differently
than had they been stored in the
ordinary object heap.


Why the first result is false ?

==比较引用并创建两个不同的对象。

I understood that for none primitive types, when we do '==',

字符串不是基元。当引用同一对象时,引用将是==


比较s == s1时,您比较的是两个不同的MyString对象。这样想你的处境

enter image description here

ss1是不同的对象,但它们的属性指向同一个toto实例。

它们是不同的对象,因为您创建它们的方式:

1
2
MyString s = new MyString("toto");
MyString s1 = new MyString("toto");

因此,s == s1将返回false。为了让它返回true,它们必须是同一个对象。你可以这样做:

1
2
MyString s = new MyString("toto");
MyString s1 = s;

结果就是这样

氧化镁


MyString的每个实例都位于不同的内存位置,因此,忘记了实例的内容,对于每两个不同的实例,==测试将导致false

对于String类,有一个很小但很重要的区别,当你分配一个String变量时,右手边的操作符是一个文本(即String s ="foo";),只有在以前没有遇到"foo"作为文本时,"foo"才会占用一个新的内存位置。如果是这种情况(即String s ="foo"; String otherS ="foo";),otherS只会引用已经存在的"foo"。

这种行为称为字符串池。


只有Interned(String.intern()字符串可以安全地与==进行比较,对于所有其他情况,您应该使用equals字符串。

在你的例子中,你定义了自己的类型EDCOX1,7,它与Java EDCOX1,3有很小的共同点,所以比较EDCOX1,9,EDCX1,10,你比较两个不同的对象的引用,这就是为什么你得到EDOCX1,11。


第一次比较失败的原因是,通过调用new创建了两个对象。现在,==操作符会比较两个内存地址,这会产生返回,因为这两个对象不在同一个内存单元中。

它使用常量字符串的原因是Java编译器EDCOX1(2),确实优化了代码。通过这种优化,相似的字符串常量被放置在同一个内存单元中。如果您执行了以下操作,那么对于您的String对象,结果将是相同的。

1
2
3
String s2 = new String("toto");
String s3 = new String("toto");
System.out.println(s2==s3); //yields false!!

你的方法是。等于(其他)。为此,您必须在myString类中实现方法equals:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyString{

    private String s;

    public MyString (String s){
        this.s = s;
    }

    public String getContent(){
        return s;
    }

    @Override
    public boolean equals(Object other){
        if(other instanceof MyString){
            MyString compareTo = (MyString) other;
            return this.s.equals(compareTo.getContent());
        }
        return false;
    }
}


由于字符串是不可变的,ToString方法的一个有用的实现是(在String类中)返回这个值。

例如,my rt.jar包含以下实现:

1
2
3
public String toString() {
return this;
}

因此,与s3相关的参考与与与s2相关的参考相同。

考虑到s1==s2语句,这是由于所有常量字符串都自动调用intern()。这意味着在编译时,s2初始化代码将被s2=s1替换,这使得断言非常明显,不是吗?


考虑到==比较引用,从s2 == s3可以看出,s2.toString()返回s2是正确的。


在字符串上使用==时,只比较引用。因此,只有在以下情况下,==才能保证返回true

1
2
String s1 ="...";
String s2 = s1;    // reference assignment!

这里,s1 == s2。在所有其他情况下,即使两个字符串包含相同的字符序列,==也可以返回或不返回true

要比较两个字符串的内容,请使用equals()

1
2
3
if (s1.equals(s2)) {
   ...
}


"=="是比较引用。但对象类中的equals()方法只是比较引用。子类中方法equals()的行为基于重写该方法的实现。


s2.ToString()正在返回字符串表示形式。因为它已经是一个字符串,所以它返回自己(这就是为什么比较是真的)。

所有字符串都分配在堆上,coparison运算符只是比较它们是否是同一个对象(这就是为什么s1!= S2)。