Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Java guaranteed to inline string constants if they can be determined at compile time

Consider this case:

public Class1 {
   public static final String ONE = "ABC";
   public static final String TWO = "DEF";
}

public Class2 {

  public void someMethod() {
    System.out.println(Class1.ONE + Class1.TWO);
  }
}

Typically you would expect the compiler to inline the ONE and TWO constants. However, is this behavior guaranteed? Can you deploy at runtime Class2 without Class1 in the classpath, and expect it to work regardless of compilers, or is this an optional compiler optimization?

EDIT: Why on earth do this? Well I have a constant that would be shared between two ends of an application (client and server over RMI) and it would be very convenient in this particular case to put the constant on a class that can only be on one side of that divide (as it is logically the one that owns that constant value) rather than have it in an arbitrary constants class just because it needs to be shared by both sides of the code. At compile time its all one set of source files, but at build time it is divided by package.

like image 398
Yishai Avatar asked Sep 10 '09 17:09

Yishai


1 Answers

It's guaranteed to be treated as a constant expression, and guaranteed to be interned by section 15.28 of the JLS:

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

  • Literals of primitive type and literals of type String (§3.10.5)
  • Casts to primitive types and casts to type String
  • The unary operators +, -, ~, and ! (but not ++ or --)
  • The multiplicative operators *, /, and %
  • The additive operators + and -
  • ...

...

Compile-time constants of type String are always "interned" so as to share unique instances, using the method String.intern.

Now, that doesn't quite say it's guaranteed to be inlined. However, section 13.1 of the spec says:

References to fields that are constant variables (§4.12.4) are resolved at compile time to the constant value that is denoted. No reference to such a constant field should be present in the code in a binary file (except in the class or interface containing the constant field, which will have code to initialize it), and such constant fields must always appear to have been initialized; the default initial value for the type of such a field must never be observed.

In other words, even if the expression itself weren't a constant, there should be no reference to Class1. So yes, you're okay. That doesn't necessarily guarantee that the concatenated value is used in the bytecode, but the bits referenced earlier guarantee that the concatenated value is interned, so I'd be hugely surprised if it didn't just inline the concatenated value. Even if it doesn't, you're guaranteed that it'll work without Class1.

like image 77
Jon Skeet Avatar answered Sep 19 '22 05:09

Jon Skeet