【问题标题】:Rules for String a == String b [duplicate]字符串 a == 字符串 b 的规则 [重复]
【发布时间】:2016-10-08 06:41:22
【问题描述】:

我正在尝试了解字符串池的工作原理以及字符串与另一个字符串相等的规则。

例如这个sn-p:

public static void main(String[] hi){
    String s1 = "lol";
    String s2 = "lol";
    String s3 = new String("lol");
    System.out.println( s1 == s2 );// true
    System.out.println( s2 == s3); // false
    s3.intern(); //line 1
    System.out.println( s1 == s3); // false
    testString(s1);

}

private static void testString(String s1){
    String s4 = "lol";
    System.out.println( s1 == s4); // true
}
  1. 在 //line 1:字符串被添加到字符串池中。由于它不等于 s1 我假设字符串池中有一个重复项。对吗?

  2. 在池中有重复的规则是什么?换句话说,即使两个字符串具有相同的字符序列,someString == someString 何时返回 false ?

PS:无论如何,我在任何地方都使用 string1.equals(string2)。我只是想更深入地了解底层机制。

【问题讨论】:

标签: java string heap-memory


【解决方案1】:

比较总是从池中获取的字符串文字(案例 s1 和 s2)与比较字符串文字或在运行时使用构造函数创建的字符串与使用 new 创建的另一个字符串时存在差异。

当完全相同的文字已经存在时,保证从字符串池中获取字符串文字。字符串对象在内部仍然使用池中的字符串,但作为一个对象有不同的引用。

String#intern(); 从池中返回对字符串的引用,这是内部使用的。

代码 sn-p 以显示此行为:

String literalOne = "abc";
String literalTwo = "abc";
String stringOne = new String("abc");
String stringTwo = new String("abc");

System.out.println("literalOne == literalTwo ? " + (literalOne == literalTwo));
System.out.println("stringOne == stringTwo ? " + (stringOne == stringTwo));
System.out.println("Internally stringOne == stringTwo ? " + (stringOne.intern() == stringTwo.intern()));
System.out.println("Internally stringOne == literalOne ? " + (stringOne.intern() == literalOne));

还有输出:

literalOne == literalTwo ? true
stringOne == stringTwo ? false
Internally stringOne == stringTwo ? true
Internally stringOne == literalOne ? true

【讨论】:

    【解决方案2】:

    == 比较引用,因此当您尝试 s1 == s3 时,您正在检查这两个引用是否指向同一个对象,这是不正确的,因为您已将 s3 创建为新对象(new String("lol" ))。所以现在字符串池有两个不同的对象,它们恰好具有相同的字符串值(“lol”),在你的代码中你有 s1,s2,s4 指向一个,s3 指向另一个。

    为了让您比较每个被引用对象的值,您必须使用 equals() 方法。

    【讨论】:

      【解决方案3】:

      您的s3.intern(); 应该是s3 = s3.intern(); 以获得正确的行为。

      【讨论】:

        【解决方案4】:

        基本上我们可以通过两种方式创建 Sting

        String str="some data" (not bound to any object like primitive data type)
        String strTwo=new String("some String"); (here strTwo object contains value)
        

        顾名思义,字符串池是存储在Java HeapMemory 中的字符串池。我们知道 String 是 java 中的特殊类,我们可以使用 new 运算符创建 String 对象,也可以在双引号中提供值。

        String Pool 之所以成为可能,是因为 String 在 Java 中是不可变的,而且它是 String interning 概念的实现。字符串池也是享元设计模式的一个例子。

        字符串池有助于为 Java 运行时节省大量空间,尽管创建字符串需要更多时间。

        当我们使用双引号创建一个字符串时,它首先在字符串池中查找具有相同值的字符串,如果找到则返回引用,否则在池中创建一个新的字符串,然后返回引用。

        但是使用 new 操作符,我们强制 String 类创建一个新的 String 对象,然后我们可以使用 intern() 方法将其放入池中或从池中引用其他具有相同值的 String 对象。强>

        作为

        public void method(){
        String s1 = "Cat";
                String s2 = "Cat";
                String s3 = new String("Cat");
        
                System.out.println("s1 == s2 :"+(s1==s2));
                System.out.println("s1 == s3 :"+(s1==s3));
        }
        

        和输出

        [![s1 == s2 :true
        s1 == s3 :false
        

        【讨论】:

          【解决方案5】:
          1. 在 //line 1:将字符串添加到字符串池中。由于它不等于 s1 我假设字符串池中有重复项。正确吗?

          不,不正确。字符串池中已经有一个字符串“lol”,因此不会创建重复项。但是,您没有对调用 intern() 的返回值做任何事情,所以 s3 仍然指的是不在池中的 String 对象。

          试试s3 = s3.intern(); 而不是s3.intern();

          1. 在池中有重复的规则是什么?换句话说,即使两个字符串具有相同的字符序列, someString == someString 何时返回 false ?

          字符串池的全部意义在于避免内存中出现重复的字符串,这样字符串池中就不会出现任何重复。

          【讨论】:

          • 好的,但是关于第 n2 点。 s1 == s2 无论这两个是在哪里创建的,都评估为 true 吗?假设它们最初都是这样实例化的:myString = "lol";
          • 当您执行String myString = "lol"; 时,您不会直接实例化一个新的String 对象。编译器足够聪明,可以让myString 引用池中已经存在的String,从而避免创建新的String 对象。
          • 好吧,我只是想知道如果例如导入了 jars 或类似的东西,行为是否会有所不同。归根结底,这并不重要,我明白了要点。
          猜你喜欢
          • 2021-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-27
          相关资源
          最近更新 更多