Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 264
Eli Sadoff Avatar asked Jun 23 '26 14:06

Eli Sadoff


2 Answers

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 ==.

like image 169
Sinkingpoint Avatar answered Jun 26 '26 06:06

Sinkingpoint


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()

like image 22
Stephen P Avatar answered Jun 26 '26 04:06

Stephen P



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!