何时“ ==”运算符成功比较字符串?

时间:2019-05-13 02:15:20

标签: java arrays string

我知道相等运算符会将引用与字符串进行比较。因此,它将检查字符串是否指向同一对象,而不是每个字符是否相等。

作为学习搜索算法的第一步,我设置了以下程序,该程序中有一个名称数组,然后检查该数组中是否存在某个名称。

第一种方法

我声明并初始化名称数组。我要求用户输入一个名称,以检查它是否出现在数组中。

这是我使用的代码-

import java.util.Scanner;

public class Strawman{

    public static void main(String[] args){

        System.out.println("Enter the name to search for:");

        Scanner scanner = new Scanner(System.in);
        String key = scanner.nextLine();

        String[] names = {"alice", "bob", "carlos", "carol", "craig", "dave", "erin", "eve", "frank", "mallory", "oscar", "peggy", "trent", "walter", "wendy"};

        for (int i = 0; i < names.length; i++){

            if (key == names[i]) {
                System.out.println("Index " + i + " has the name " + key);
            } 
        }
    }

}

该程序的运行之一显示在以下屏幕截图中- program output

按预期,因为我使用==运算符比较字符串,所以即使出现在初始数组中,也无法在数组中找到名称“ oscar”。根据我对相等运算符如何比较字符串引用的理解,此输出是预期的。

但是,我不理解为什么我不声明用户输入而是将要搜索的名称声明为字符串来解释该程序为什么起作用。

第二种方法

要搜索的名称“ oscar”已声明为字符串,而不是要求用户输入-

public class Strawman2{

    public static void main(String[] args){

        String[] names = {"alice", "bob", "carol", "craig", "carlos", "dave", "eve", "fred", "greg", "gregory", "oscar", "peter"};
        String key = "oscar";

        for (int i = 0; i < names.length; i++){

            if (names[i] == key){
                System.out.println("Index " + i + " has name " + key);
            }

        }

    }

}

现在,如果我运行该程序,则会在数组中找到名称“ oscar”- output_approach2

有人可以解释这两种情况的区别吗?

3 个答案:

答案 0 :(得分:6)

这是因为在第二种方法

String key = "oscar";

重复使用由填充的字符串常量池中的实例

String[] names = {"alice", "bob", "carol", "craig", "carlos", "dave", "eve", "fred", "greg", "gregory", "oscar", "peter"};

将启动键变量的方式更改为:

String key = new String("oscar");

它的行为与第一种方法相同,因为您绕过了字符串常量池,并且key变量现在将引用内存中的另一个对象。

  

有关字符串常量池的更多信息:   String Constant Pool

答案 1 :(得分:2)

这是因为编译器重用了编译时已知的字符串文字中的字符串实例。因此,它们通过了对象相等性检查。可以重复使用,因为字符串是不可变的对象。

在编译时不知道和/或显式创建为new String对象的字符串不受此优化的约束,并且始终会产生新的对象。

答案 2 :(得分:1)

在两种情况下,保证==可以(根据需要)用于字符串测试:

  1. 您显式创建了一个String对象,并且知道要在两个不同的地方使用相同的引用。

  2. 您肯定知道要比较的两个字符串都已被锁定。请注意,字符串文字总是 1 内联。

    从技术上讲,插入字符串是在生命周期中某个时间调用String::intern的结果。 (请参阅JLS 3.10.5javadoc。)尽管没有在任何地方指定术语“字符串池” 2 。

还有其他任何==可能会给出错误的答案。

而且...这两种情况在实际程序中很少出现。


1-并非完全100%正确:考虑作为常量表达式中子表达式的文字。但是,这不会影响==运算符的行为。

2-我发现的最接近的是“最初为空的字符串池,由javadocs中的类String私有维护。但是当前的javadocs,JLS和JVM规范不使用短语“字符串池” “字符串常量池” 或其他任何形式的我可以找到。