Java 字符串池的意外行为

Java 字符串池的意外行为,java,string-comparison,Java,String Comparison,我有以下测试: public class EqualityTest { String one = new String("Hello world"); String two = new String("Hello ") + new String("world"); @Test public void testStringPool() { assertFalse(one == two); // FALSE!!! assert

我有以下测试:

public class EqualityTest
{
    String one = new String("Hello world");
    String two = new String("Hello ") + new String("world");

    @Test
    public void testStringPool()
    {
        assertFalse(one == two); // FALSE!!!
        assertTrue(one.equals(two));
        assertTrue(one.intern().equals(two.intern()));
    }
}
我原以为,由于Java的字符串池性质,VM会分配一个和两个指向池中相同字符串的字符串。为什么在这种情况下我的理解是错误的?

每当您使用new操作符时,总是在Heap上创建一个新对象。因此,即使字符串helloworld在文本池中可用,它也不会被引用。事实上,您正在堆上创建4个对象:-

Hello World-->新字符串Hello World; Hello-->新建StringHello; 世界-->新世界; 同样,Hello World-->新建StringHello+新建StringWorld; 除此之外,在文字池中还会创建3个文字-Hello World、Hello和World

总共有7个对象

另一方面,您是否使用以下方法创建了字符串:-

String str = "Hello World";
String str2 = "Hello " + "World";
同样,这里将在文字池上创建3个文字-Hello World、Hello和World,但最后两个文字的串联将引用第一个文字

因此,两个字符串引用指向相同的文本,因此它们现在将相等。

每当您使用new操作符时,总是在Heap上创建一个新对象。因此,即使字符串helloworld在文本池中可用,它也不会被引用。事实上,您正在堆上创建4个对象:-

Hello World-->新字符串Hello World; Hello-->新建StringHello; 世界-->新世界; 同样,Hello World-->新建StringHello+新建StringWorld; 除此之外,在文字池中还会创建3个文字-Hello World、Hello和World

总共有7个对象

另一方面,您是否使用以下方法创建了字符串:-

String str = "Hello World";
String str2 = "Hello " + "World";
同样,这里将在文字池上创建3个文字-Hello World、Hello和World,但最后两个文字的串联将引用第一个文字

因此,两个字符串引用指向相同的文本,因此它们现在是相等的

我原以为,由于Java的字符串池性质,VM会分配一个和两个指向池中相同字符串的字符串

只有字符串常量会自动插入。因此,如果您的代码是:

String one = "Hello world";
String two = "Hello " + "world";
。。。那么1和2的值就相同了。因为您使用了新的字符串…,所以这些表达式不是常量表达式,所以它们不是临时表达式。当然,这些文字仍然被拘留。。。但不是从文本创建的字符串

有关常量表达式的详细信息,请参见

我原以为,由于Java的字符串池性质,VM会分配一个和两个指向池中相同字符串的字符串

只有字符串常量会自动插入。因此,如果您的代码是:

String one = "Hello world";
String two = "Hello " + "world";
。。。那么1和2的值就相同了。因为您使用了新的字符串…,所以这些表达式不是常量表达式,所以它们不是临时表达式。当然,这些文字仍然被拘留。。。但不是从文本创建的字符串


有关常量表达式的详细信息,请参阅。

每当使用新字符串xyz创建字符串对象时,都会创建一个新的对象引用

例如:当您只处理文本时,将使用字符串池性质

String one = "Hello world";
String two = "Hello "+ "world";

System.out.println(one==two);

将打印为true。

每当使用新字符串xyz创建字符串对象时,将创建一个新的对象引用

例如:当您只处理文本时,将使用字符串池性质

String one = "Hello world";
String two = "Hello "+ "world";

System.out.println(one==two);

将打印为真。

我数了4个以上:Hello-world-literal,一个对象,两个对象,Hello-literal,world-literal,new-StringHello-object和new-Stringworld-object=>我会说7个对象。@assylias。是的,我漏掉了文字。谢谢:或者你可以用+=操作符更简洁一些。@TheBlueCat和where确切位置?String str=Hello;字符串str2+=世界;我数了4个以上:Hello-world-literal,1个对象,2个对象,Hello-literal,world-literal,new-StringHello-object和new-Stringworld-object=>我会说7个对象。@assylias。是的,我漏掉了文字。谢谢:或者你可以用+=操作符更简洁一些。@TheBlueCat和where确切位置?String str=Hello;字符串str2+=世界;那不是复制品。这个问题是关于字符串实习的。@RobertHarvey你是对的,答案有点重复,但我猜不是重复的问题。值得注意的是:在C中,这是正确的,因为在大多数情况下比较两个字符串的引用并不是特别有意义。请看。@RobertHarvey那么,在C语言中,谁比较了对对象的引用呢?这似乎比Java as==更落后,只是比较了String.class中的方法,该方法由Object class.equals覆盖,用于测试值是否相等。这在C语言中是一样的吗?对不起,我离题了,我只是有点困惑。@TheBlueCat:为了比较引用,你可以使用。要点是,在C中,==用于比较两个字符串的更常见场景
一封接一封,这不是重复的。这个问题是关于字符串实习的。@RobertHarvey你是对的,答案有点重复,但我猜不是重复的问题。值得注意的是:在C中,这是正确的,因为在大多数情况下比较两个字符串的引用并不是特别有意义。请看。@RobertHarvey那么,在C语言中,谁比较了对对象的引用呢?这似乎比Java as==更落后,只是比较了String.class中的方法,该方法由Object class.equals覆盖,用于测试值是否相等。这在C语言中是一样的吗?对不起,我离题了,我只是有点困惑。@TheBlueCat:为了比较引用,你可以使用。关键是,在C中,==用于更常见的场景,即逐字母比较两个字符串。