Related to String interning
Asked Answered
S

4

18
public static void main(String[] args) {

    String a = new String("lo").intern();
    final String d = a.intern();
    String b = "lo";
    final String e = "lo";
    String c = "Hello";
    System.out.println(b==a);//true
    System.out.println(d==a);//true
    System.out.println(e==a);//true
    System.out.println(c=="Hel"+a); //why is this false? when e==a is true
    System.out.println(c=="Hel"+d); //why is this false?
    System.out.println(c=="Hel"+b); //why is this false?
    System.out.println(c=="Hel"+e); //this is true

}

This results in

true
true
true
false
false
false
true

The expression e==a is true implies same reference. So why the last expression is true but the 4th to last ie c== "Hel"+a is false?

Sapsago answered 30/12, 2014 at 7:38 Comment(5)
I think all of the last four should be false. Let me try this example.Blastocoel
have u tried with equals()Tweak
I came across a similar question and while it was answered, it was also suggested that unless necessary its usually not worth interning strings.Toque
@ben yeah I know. I recently came across the interning concept while reading about garbage collection and stringaSapsago
It's certainly worth learning about @SumeetSharma; I'm not discrediting the question. Just pointing out that it isn't entirely practicalToque
P
16

The expression

"Hel" + a

Is not a compile time constant. Actually, it compiles to:

new StringBuilder().append("Hel").append(a).toString()

(or similar) which creates a new String object at runtime.

However, because e is final, the compiler can determine that the concatenation of "Hel" and e's value is a constant value, and so interns it.

Paphlagonia answered 30/12, 2014 at 7:43 Comment(2)
instead of toString() i think String.valueOf() will be called which will call toSTring() internally.Phototonus
@bohemian can you tell c=="Hel"+d is false? here d is final ..??Sapsago
A
10

all these strings are calculated in runtime, this is why they are different

System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?

this one calculated during compile time, because e is final:

System.out.println(c=="Hel"+e); //this is true

if you change code to this:

    System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
    System.out.println(c==("Hel"+d).intern()); //why is this false?
    System.out.println(c==("Hel"+b).intern()); //why is this false?

all of them will produce true

Acrospire answered 30/12, 2014 at 7:44 Comment(4)
Do you have a quote from the JLS that "Hel"+e is a compile time constant because e is final? That's a new one for me.Blastocoel
@Blastocoel I don't have exact quote, but java compiler evaluates constant expressions (in this case "Hel" + e), as soon as e is final - compiler assume this is constantCactus
@Blastocoel ExpressionsSaury
JLS 3.10.5: "Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals."Oligosaccharide
C
5

Java compiler (javac) translates your code in Java to byte code which is executed by the JVM. It also does some optimizations for you. You can check the generated byte code using javap utility with -c parameter

Concatenation with final String

c==a is true because c is final Here is the byte code for this snippet (last comparison only):

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String Hello
   2:   astore_2
   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   aload_2
   7:   ldc     #2; //String Hello
   9:   if_acmpne       16
   12:  iconst_1
   13:  goto    17
   16:  iconst_0
   17:  invokevirtual   #4; //Method java/io/PrintStream.println:(Z)V
   20:  return

}

As you see the java compiler has merged the "Hel" with "lo" and just comparing two string leterals "Hello". Java interns string literals by default - that's why it returns true

Concatenation with non-final String

If you are concatenating the string literal with non-final String variable, the byte code will be different:

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String lo
   2:   astore_1
   3:   ldc     #3; //String Hello
   5:   astore_2
   6:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   9:   aload_2
   10:  new     #5; //class java/lang/StringBuilder
   13:  dup
   14:  invokespecial   #6; //Method java/lang/StringBuilder."<init>":()V
   17:  ldc     #7; //String Hel
   19:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:  aload_1
   23:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   26:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   29:  if_acmpne       36
   32:  iconst_1
   33:  goto    37
   36:  iconst_0
   37:  invokevirtual   #10; //Method java/io/PrintStream.println:(Z)V
   40:  return

}

Here we are comparing the result of java/lang/StringBuilder.toString:()Ljava/lang/String; method which obviously returns another object - it is equal to "Hello" by value but not by reference

You can find more details on comparing strings in this stackoverflow question

Coon answered 30/12, 2014 at 7:47 Comment(3)
not well versed with bytecode can you add some comments for better explanationSapsago
@SumeetSharma I have added some more details. Hope it's clear nowCoon
Thanks a lot for the insight into bytecode. Was very useful understanding the == operation's under the hood stuff. But I found Boehmias answer more relevant to what I was looking for. :) Thanks anyway. I have given an upvote.Sapsago
T
1

Even though you are using intern() method, you have to still remember that == compares by reference and not value.

So in the cases of

System.out.println(c=="Hel"+a);
    System.out.println(c=="Hel"+d); 
    System.out.println(c=="Hel"+b); 

"Hel" + a or "Hel" + d or "Hel" + b will have a new reference in memory that is not equal to that of c.

in the final case since the string value is final, the evaluation happens at compile time instead of runtime as optimization since it will never change. Also if you are thinking when you define string literal, Java internally interns them.

Taler answered 30/12, 2014 at 7:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.