简体   繁体   中英

What is going on with equality in JShell/Java 9?

I've been using JShell a bit just to test it out, and today I came across quite the interesting bit of behavior.

jshell> String a = "A"
a ==> "A"

jshell> String b = "A"
b ==> "A"

jshell> a == b
$4 ==> true

jshell> "A" == "A"
$5 ==> true

I was first wondering if this was a feature of Java 9, and I checked it out by compiling and running this program with Java 9

public class Equus {
    public static void main(String... args) {
        String a = "A";
        String b = "A";
        System.out.println("a == b");
        System.out.println(a == b);
        System.out.println("\"A\" == \"A\"");
        System.out.println("A" == "A");
    }
}

And interestingly enough I got

 a == b true "A" == "A" true 

As my output as well. What's going on here? Why are a and b equal to each other and why is "A" == "A" true?

Why shouldn't it be? This behaviour is exhibited in previous Java versions as well - String literals are interned.

As you know, == checks for reference equality - the two variables have the same memory address. When a String is interned, all references of that string point to the intern pool and thus will be equal using == .

I just wanted to add this demonstration alongside Sinkingpoint's fine answer.
It's not safe to use == on Strings unless you know the origin of each, since a String that is built-up in some way (such as the new String("A") in Eli's comment or the .toString() used here) is not the same reference even if the two do use the same underlying character array.

class Main
{
  public static void main(String[] args)
  {
    String oneA = "A";
    String twoA = "A";
    String three = new StringBuilder().append('A').toString();

    // We expect constant literals to be ==
    System.out.print("A == A -> ");
    System.out.println("A" == "A");

    // Variables assigned the same literal are also ==
    System.out.print("oneA == twoA -> ");
    System.out.println(oneA == twoA);

    // but a built-up String var is not == to the "literal" var.
    System.out.print("oneA == three -> ");
    System.out.println(oneA == three);

    // If we intern() them they are again ==
    System.out.print("oneA.intern() == three.intern() -> ");
    System.out.println(oneA.intern() == three.intern());

    // and of course, .equals() is always safe.
    System.out.print("oneA .equals three -> ");
    System.out.println(oneA.equals(three));
  }
}

The output from this (run on https://repl.it/languages/java ) is:

A == A -> true
oneA == twoA -> true
oneA == three -> false
oneA.intern() == three.intern() -> true
oneA .equals three -> true

You can safely use string1.equals(string2) or string1.intern() == string2.intern()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM