为什么Java没有警告= =“某事”?

时间:2010-05-14 18:44:22

标签: 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");
}

我意识到为什么表达式是不真实的,但是AFAIK,a永远不能等于String文字“某事”。编译器应该意识到这一点,并且至少警告我,我是一个正在深夜编码的白痴。

澄清 这个问题不是关于比较两个String对象变量,而是将String对象变量与String文字进行比较。我意识到以下代码很有用,并且会产生与.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");
}

在这种情况下,a和b实际上可能指向内存中的相同区域,即使它不是因为实习。但是在第一个例子中,唯一的原因是,如果Java在幕后做了一些对我没用的东西,而且我不能利用它。

跟进问题 即使a和string-literal都指向内存中的相同区域,对于我在上面的表达式中如何有用。如果该表达式返回true,那么我可以用这些知识做什么有用的东西,是吗?如果我正在比较两个变量,那么是的,那些信息会很有用,但是对于变量和文字它有点无意义。

9 个答案:

答案 0 :(得分:13)

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

关于字符串实习的Java注释

答案 1 :(得分:8)

编译器警告往往是关于明显错误的事情(永远不会是真或假的条件)或不安全(未经检查的强制转换)。使用==是有效的,在极少数情况下是有意的。

我相信所有CheckstyleFindBugsPMD都会对此发出警告,并且可选择在半睡半醒或其他情况下无法实施的许多其他不良行为;)。

答案 2 :(得分:4)

由于:

  • 如果使用常量和interned字符串
  • ,您可能真的想使用==
  • 编译器应仅为String创建一个例外,而不是其他类型。我的意思是 - 每当编译器遇到==时,它应检查操作数是否为Strings以发出警告。如果参数为Strings,但被称为ObjectCharSequence,该怎么办?

checkstyle发出错误的理由是新手程序员经常这样做。如果你是新手,我很难配置checkstyle(或pmd),甚至不知道它们。

另一件事是比较字符串并且有一个文字作为操作数之一的实际情况。首先,最好使用常量(static final)而不是文字。另一个操作数来自哪里?它可能来自相同的常量/文字,代码中的其他位置。所以==会起作用。

答案 3 :(得分:3)

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

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

因此,没有尝试自动执行此操作。

如果您考虑缓存等问题,那么您可能需要进行此测试。

答案 4 :(得分:2)

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

答案 5 :(得分:1)

编译器并不关心您是否正在尝试对文字进行身份比较。也可以说,成为代码保姆不是编译器的工作。如果你想捕捉这样的情况,请寻找类似于lint的工具。

答案 6 :(得分:1)

“我知道为什么表达式是不真实的,但是AFAIK,一个永远不能等于字符串文字”的东西。“

为了澄清,在给出的示例中,expersion总是为TRUE, a 可以是==和equals()到String文字,并且在给定的示例中它总是==和等于( )。

具有讽刺意味的是,你似乎已经为你自己的论点提供了罕见的反例。

答案 7 :(得分:0)

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

现在,对于字符串而言,你想要==的可能性远远低于用户定义类型,但这并不能保证你不会想要它,甚至如果确实如此,这意味着编译器必须特殊检查特殊情况字符串,以确保您没有使用==

另外,因为字符串是不可变的,所以JVM可以自由地生成每个equals()共享相同实例的字符串(以节省内存),在这种情况下,它们也相等{{1 }}。因此,根据JVM的作用,==很可能会返回true。你给出的例子实际上是一个有很大机会的例子,因为它们都是字符串文字,所以JVM很容易使它们成为相同的字符串,它可能会。当然,如果你想看看JVM是否让两个字符串共享同一个实例,你 使用==而不是==,所以有一个想要在字符串上使用equals()的正当理由。

因此,编译器无法充分了解您正在做的事情,知道使用==代替==应该是错误。如果你不小心这会导致错误(特别是如果你习惯了像C ++那样重载equals()的语言而不是单独的==函数),但编译器只能这样做非常适合你。使用equals()而不是==有合理的原因,因此编译器不会将其标记为错误。

答案 8 :(得分:0)

有些工具会警告你这些结构;随意使用它们。但是,当你想在字符串上使用==时,有一些有效的情况,并且更糟糕的语言设计是警告用户一个完全有效的构造而不是警告它们。当你使用Java一年左右时(我会打赌你尚未达到那个阶段的好钱)你会发现避免像这样的结构是第二天性。