4

Why is this code returning "false" instead of "true":

package com.company;


public class Main {

    public static void main(String[] args) {

        String fullName = "Name Lastname";
        String name = "Name ";
        String lastName = "Lastname";
        String firstNamePlusLastName = name + lastName;

        System.out.println(fullName == firstNamePlusLastName);

    }
}

If I remember correctly:

String firstNamePlusLastName = name + lastName;

Should create a String that points to an existing address in memory (String pool) because we already have declared a String with value: "Name Lastname", shouldn't it be automatically interned into String pool and shouldn't the output be "true" since we already have string with same value in String pool as String firstNamePlusLastname ?

EDIT:

I know I should use .equals() method when testing two strings for equality of content, but I don't want to do that in the example above, I actually do want to test for reference equality, and based on Java interning the two strings that I compare in the code above should be equal, but they are not, they should point to the same address in memory as they have same content and neither of the Strings was created using "new" keyword. I want to know why is this happening.

  • 1
    You have to use `equals` to compare two string objects. – Steve May 22 '17 at 20:44
  • 5
    Possible duplicate of [How do I compare strings in Java?](https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – Jeffrey Chung May 22 '17 at 20:45
  • Possible duplicate of [What is the difference between "text" and new String("text")?](https://stackoverflow.com/questions/3052442/what-is-the-difference-between-text-and-new-stringtext) – KevinO May 22 '17 at 20:48
  • 4
    I believe the JLS insists on this being false. It would be a different matter had you made the references final. – Bathsheba May 22 '17 at 20:49
  • In what way is `firstNamePlusLanstName = name + lastName` a [String Literal](http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5)? – KevinO May 22 '17 at 20:58
  • @KevinO: It doesn't have to be a string literal - it has to be a constant expression. It can still involve concatenation, provided the operands are *also* string constant expressions. From a few paragraphs into the link you showed: "This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern." – Jon Skeet May 22 '17 at 20:59
  • @JonSkeet, a fair point. However, the `constant expression`, if I read it correctly requires *literals* of type `String` in order to be a constant expression. – KevinO May 22 '17 at 21:04
  • 3
    @KevinO: Nope, it can also be a concatenation of other string constants... and static final fields initialized with string constants, or final local fields initialized with string constants are also constant expressions. So yes, there'll always be a string literal somewhere (unless everything is null) but that's not the same thing. – Jon Skeet May 22 '17 at 21:05
  • 1
    How about my [answer](https://stackoverflow.com/questions/44121813/java-string-instantiation/44122164#44122164), sir. – holi-java May 22 '17 at 21:09
  • @JonSkeet, you are, of course, correct that it is constants, until some point. There must be literal there somewhere; it can't be constants all the way down, otherwise I'm not sure how JLS 15.28 makes any sense. But perhaps I'm just missing something. – KevinO May 22 '17 at 21:20
  • @KevinO: I hadn't checked, but I was wondering about `final String x = null; String y = x + x;` - but I've checked now, and that *is* performed at execution time. (There's no "nullnull" constant in the class file.) – Jon Skeet May 22 '17 at 21:23
  • [Turtles!](http://cosmology.carnegiescience.edu/timeline/1610/turtles-all-the-way-down) – Dawood ibn Kareem May 22 '17 at 21:25

3 Answers3

1

String Constant Pool create at compiling-time. it only using strings from pool when you concat String literals / final variables / final fields except final parameters, for example:

Concat Literals

String fullName = "Name Lastname";
String firstNamePlusLastName = "Name " + "Lastname";

System.out.println(fullName == firstNamePlusLastName);// true

Concat Final Variables

String fullName = "Name Lastname";
final String name = "Name ";
final String lastName = "Lastname";
String firstNamePlusLastName = name + lastName;

System.out.println(fullName == firstNamePlusLastName);//true
holi-java
  • 29,655
  • 7
  • 72
  • 83
  • 1
    Not just any finals - they have to be final locals or static final fields, and they have to be initialized with constant expressions. – Jon Skeet May 22 '17 at 21:17
  • @JonSkeet I think I need to fix it,:). since the `final` parameters not does. thanks very much. – holi-java May 22 '17 at 21:28
  • 1
    @JonSkeet: there is no need to constrain the type of variable. The specification says, any `final` variable that is initialized with a compile-time constant (and is of primitive type or `String`), is a compile-time constant. This rules out parameters automatically, as parameters can’t have an initializer. However, this implies that fields do *not* have to be `static` to be compile-time constants. (Though, constant non-`static` fields are a waste of memory…) – Holger Nov 23 '17 at 16:30
  • @Holger: Interesting, yes. – Jon Skeet Nov 23 '17 at 16:33
0

Because you must use .equals() to strings

fullName.equals(firstNamePlusLastName)

== tests for reference equality (whether they are the same object), meaning exactly the same, the same reference even.

.equals() refers to the equals implementation of an object, it means, for string, if they has the same chars in the same order.

Consider this:

    String a = new String("a");
    String anotherA = new String("a");
    String b = a;
    String c = a;

a == anotherA -> False;
b == a -> True
b == c -> true
anotherA.equals(a) -> True
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
  • Yes, and if you create a string like this: String someString = "Some content"; and you create another like this: String anotherString = "Some content"; And test for equality with "==" it returns true, because the first String was implicity interned by JVM, but it's not the case with the example above, I just want to know why. –  May 22 '17 at 20:51
  • 1
    I think this still doesn't answer the question. OP wants to know why the concatenation isn't done at compile time, then the result added to the string pool. – Dawood ibn Kareem May 22 '17 at 20:56
  • @Damian Lattenero, the use Dawood is right, as confirmed by Jon Skeet and KevinO. –  May 22 '17 at 21:03
-1

String literals are interned. When you create a string through any method that isn't a literal (calling new String(), reading from input, concatenation, etc) it will not be automatically interned. When you called String firstNamePlusLastName = name + lastName; You concatenated name and lastName creating a new string. This is not a literal and you didn't call intern so this string is not added to the string pool.

puhlen
  • 8,400
  • 1
  • 16
  • 31
  • No, string *constants* are interned. From 3.10.5: "This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern." – Jon Skeet May 22 '17 at 20:59