为什么';t Java关于a的警告==";什么;?

为什么';t Java关于a的警告==";什么;?,java,language-design,Java,Language Design,这听起来可能很愚蠢,但为什么Java编译器不警告以下if语句中的表达式: String a = "something"; if(a == "something"){ System.out.println("a is equal to something"); }else{ System.out.println("a is not equal to something"); } 我知道为什么这个表达式是不真实的,但好吧,a永远不能等于字符串文字“something”。编译器应该意识到这一

这听起来可能很愚蠢,但为什么Java编译器不警告以下if语句中的表达式:

String a = "something";
if(a == "something"){
  System.out.println("a is equal to something");
}else{
  System.out.println("a is not equal to something");
}

我知道为什么这个表达式是不真实的,但好吧,a永远不能等于字符串文字“something”。编译器应该意识到这一点,并至少警告我,我是一个白痴,在深夜编写代码

澄清 这个问题不是关于比较两个字符串对象变量,而是关于比较字符串对象变量和字符串文本。我意识到以下代码很有用,并且会产生与
.equals()
不同的结果:

在这种情况下,a和b实际上可能指向内存中的同一区域,即使不是因为实习。但是,在第一个示例中,唯一的原因是Java在幕后做了一些对我没有用处的事情,而我不能利用这些事情来发挥自己的优势

后续问题
即使a和string literal都指向内存中的同一区域,在上面的表达式中,这对我来说有什么用处呢。如果这个表达式返回true,我就不能用这些知识做任何有用的事情,是吗?如果我比较两个变量,那么是的,这些信息会很有用,但是对于一个变量和一个文本来说,这是毫无意义的。

实际上,如果Java选择插入字符串,它们确实可以是相同的引用。String interning的概念是在运行时一个不同的字符串只有一个值

关于字符串实习的Java注释


编译器并不关心您是否试图对文本进行标识比较。也有人认为,编译器的工作不是做代码保姆。如果您想捕捉这种情况,请寻找类似lint的工具。

事实上,有时可能是真的,这取决于Java是从其内部字符串缓存中获取现有字符串,创建第一个声明然后存储它,还是将其用于两个字符串声明。

因为:

  • 如果使用常量和字符串,实际上可能需要使用
    =
  • 编译器应该只对
    字符串
    进行例外,而不对其他类型进行例外。我的意思是-每当编译器遇到
    ==
    时,它应该检查操作数是否为
    字符串,以便发出警告。如果参数是
    字符串
    ,但被称为
    对象
    字符序列
    ,该怎么办
发布错误的理由是新手程序员经常这样做。如果您是新手,我很难配置checkstyle(或pmd),甚至很难了解它们


另一件事是比较字符串时的实际场景,其中一个操作数是一个文本。首先,最好使用常量(
static final
)而不是文本。另一个操作数从何而来?它很可能来自代码中其他地方的相同常量/文字。因此,
=
会起作用。

编译器警告往往是关于明显错误(决不能为真或假的条件)或不安全(未经检查的强制转换)的内容。==的使用是有效的,在某些罕见的情况下是有意的


我相信所有这些,并将警告大家这一点,以及我们在半睡半醒或丧失行为能力时可能遇到的许多其他不良行为;)

根据上下文,身份比较和价值比较都是合法的

我能想到的查询很少,其中有一个确定性的自动算法可以明确地指出其中一个是错误的

因此,没有人试图自动执行此操作


如果您考虑缓存之类的事情,那么在某些情况下您可能希望执行此测试。

在某些情况下,您实际上关心的是处理的对象是否完全相同,而不是两个对象是否相等。在这种情况下,您需要
=
而不是
equals()
。编译器无法知道您是否真的想要比较引用的相等性或它们指向的对象

现在,与用户定义的类型相比,您希望字符串使用
=
的可能性要小得多,但这并不能保证您不需要它,即使它需要,也意味着编译器必须特别检查特殊情况下的字符串,以确保您没有对它们使用
=

此外,由于字符串是不可变的,JVM可以自由地使每个
equals()
都相等的字符串共享同一个实例(以节省内存),在这种情况下,每个
=
它们也相等。因此,根据JVM的工作,
==
很可能返回true。您给出的示例实际上是一个很有可能的例子,因为它们都是字符串文本,所以JVM很容易将它们变成相同的字符串,而且可能会。当然,如果您想查看JVM是否使两个字符串共享同一个实例,则必须使用
=
而不是
equals()
,因此有一个合理的理由要在字符串上使用
=

因此,编译器无法充分了解您正在做的事情,从而知道使用
==
而不是
equals()
应该是一个错误。如果你不小心,这可能会导致错误(特别是如果你习惯了C++之类的语言,它会重载<代码> = = /COD>而不是单独的<代码>(相等)(< /代码>函数),但是编译器只能为你做这么多。使用
==
而不是
equals()
是有正当理由的,因此编译器不会将其标记为错误。

String a = iReturnAString(); String b = iReturnADifferentString(); if(a == b){ System.out.println("a is equal to b"); }else{ System.out.println("a is not equal to b"); }