-1
package foo.library;

public class Consts {
  public static final String FOO = "foo";
}

package bar.code;

public class codeFuncs {    
  public String func1() {
    return FOO;
  }

  if(func1() == FOO) ....
}

(The const is in a library included as a dependency.)

Is this guaranteed by Java to always return true? Or can the compiler inline the string, and not intern/memoize the string, and then it might return false, since the compiler created two different objects?

Or does the static final guarantee that it uses the defined String Object, and it won't inline the text?

Ariel
  • 25,995
  • 5
  • 59
  • 69
  • 2
    What do you mean by _inline the string_? `FOO` and the return value of `func1()` are references to objects. Both of those will evaluate to the same reference value. – Sotirios Delimanolis Feb 10 '23 at 19:07
  • @SotiriosDelimanolis I have been told that String constants of this type are essentially inlined by the compiler. If this is not true, then please tell me that. – Ariel Feb 13 '23 at 04:24
  • How do you define _inline_? – Sotirios Delimanolis Feb 13 '23 at 05:43
  • @SotiriosDelimanolis I was told that `if(func1() == FOO)` becomes `if(func1() == "foo")` - as if the string is copied in as text (which makes me worry it's a different string object). Note: I am aware that optimizing compilers will make it the same object, my question is does the language spec guarantee this. – Ariel Feb 13 '23 at 07:26
  • Yes, Java does replace the use of [constant variables](https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.29) with their value, eg. https://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling. But this doesn't matter here, because the String value is interned anyway. – Sotirios Delimanolis Feb 13 '23 at 15:35

3 Answers3

2

Yes it will always return true. But static has nothing to do with it. It would always return true even if declared as an instance field. And using String FOO = new String("foo") would also return true because in all cases you are returning the same instance from func1() so you are basically doing:

System.out.println(FOO == FOO);

The difficulty is when you want to compare multiple different instances of "foo" to FOO.

String FOO = new String("foo"); // static or not
public String func1() {
    return "foo";
}
System.out.println(func1() == FOO);

Prints false since "foo" is a string literal and as such is put in the string pool and FOO is not. So you're comparing a string pool reference to some other reference of the same String.

System.out.println(new String("foo") == new String("foo")); //false- different refs
System.out.println("foo" == "foo"); // true - same refs via string pool

prints

false
true

Remember, the same String literals always return the same reference.

System.out.println(System.identityHashCode("foo"));
System.out.println(System.identityHashCode("foo"));
System.out.println(System.identityHashCode("foo"));
System.out.println(System.identityHashCode("bar"));
System.out.println(System.identityHashCode("bar"));
System.out.println(System.identityHashCode("bar"));

prints something like

1995265320
1995265320
1995265320
746292446
746292446
746292446
WJS
  • 36,363
  • 4
  • 24
  • 39
  • Is user16320675's answer wrong? – Ariel Feb 10 '23 at 19:43
  • I have edited it to clarify that it's a separate class - the consts are actually a completely separate library, included as a dependency. – Ariel Feb 13 '23 at 04:22
  • The other answer only returned false because the value of FOO was changed to some other String so the references were different. Well of course that will return false. But imo, that is not what you asked or implied. And it also would not make it a constant, as indicated by the `static final` declaration (and you did identity it as a constant). So the answer is that your code above will always return true. – WJS Feb 13 '23 at 14:31
1

No, it is not guaranteed that it will always return true.

The compiler does indeed inline the static final field. Well, not sure if we can call that inline - the value will be added to the constant pool of the class(es) using it, kind of avoiding to have to access it from the original class. So, if the test is in a different file as the constant and the function, the value of the constant can be changed without re-compiling the file doing the test. In this case it will return false.

Notes:

  • this also affects other type of constants, like int or double;
  • If (re-)compiling all files, that will never happen, it will always result in true.
  • can easily happen when updating some library and its public part was changed (it should not)
  • (obviously?) if all usages of the constant are in the same file, it will never return false (it will always be compiled together)
  • even using equals() it will return false if all involved files are not re-compiled!

Simple to test:

Holder.java:

public class Holder {
    public static final String FOO = "foo";
    public static String func() { return FOO; }
}

Main.java:

public class Main {
  public static void main(String... args) {
    System.out.println(Holder.func() == HolderB.FOO);
   // or
    System.out.println(Holder.func().equals(HolderB.FOO));
  }
}
  • Compile both files - true will be output;
  • change to ... FOO = "bar";;
  • compile only Holder.java - output will be false.
user16320675
  • 135
  • 1
  • 3
  • 9
0

As far as I am aware, this will return true. When making strings using the literal ", the string pool will return an instance of an existing string with the specified content, if it exists.

In this case, the code compiles to:

public String func1() {
    return "foo";
}

if (func1() == "foo") ...

The literals are the same, which means that the string instance resulting from the literals will also be the same, making == yield true.

0x150
  • 589
  • 2
  • 11
  • https://imgur.com/a/2J6M0Qx testing it, I was correct. It does return true. – 0x150 Feb 10 '23 at 18:38
  • I know it returns true in current compilers, but does the language guarantee that a string pool is used? Is that an implementation artifact, or something the language requires? – Ariel Feb 10 '23 at 18:49
  • @Ariel generally, it's not required for an jvm implementation to use a string pool, which is why it's generally not recommended to use == anywhere near strings. It saves performance tho, so you'll find virtually no jvm that doesn't use a string pool – 0x150 Feb 10 '23 at 18:50