자바가 컴파일 타임에 결정할 수 있다면 문자열 상수를 인라인으로 보장합니까?

StackOverflow https://stackoverflow.com/questions/1406616

  •  05-07-2019
  •  | 
  •  

문제

이 사례를 고려하십시오 :

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);
  }
}

일반적으로 컴파일러가 하나와 두 상수가 인라인 될 것으로 기대합니다. 그러나이 행동이 보장됩니까? ClassPath에서 Class1이없는 런타임 Class2에 배포 할 수 있으며 컴파일러에 관계없이 작동 할 것으로 예상 할 수 있습니까? 아니면 선택적 컴파일러 최적화입니까?

편집 : 왜 지구상에서 이렇게합니까? 글쎄, 나는 응용 프로그램의 두 끝 (RMI를 통한 클라이언트 및 서버) 사이에 공유되는 상수를 가지고 있으며이 특정 경우에 해당 분할의 한쪽에만있을 수있는 클래스에 상수를 두는 것이 매우 편리합니다 (). 코드의 양쪽에 의해 공유해야하기 때문에 임의의 상수 클래스에있는 것이 아니라 그 상수 가치를 소유하는 것이 논리적으로 이루어지기 때문입니다. 컴파일 타임에는 하나의 소스 파일 세트이지만 빌드 시점에는 패키지로 나뉩니다.

도움이 되었습니까?

해결책

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.

다른 팁

Compiling that with javac 1.6.0_14 produces the following bytecode:

public void someMethod();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String ABCDEF
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

So the strings are concatenated at compile time and the result is included in Class2's constant pool.

It won't be inlined by the compiler but by the interpreter at runtime and if possible converted to assembly code.

It cannot be guaranteed, because not all the interpreters ( JVM's ) work the same way. But the most important implementations will do.

Unfortunately I don't have a link to sustain this :(

I suspect, but don't know for sure, that this will work, but it doesn't sound like a good idea.

The "normal" ways to do this are:

  1. Put the constants in a package that's shared between the client and the server. Presumably, there is such a package, because that's where the interfaces go.
  2. If there's no such package, create 2 classes with the shared constants: one for the server and one for the client.

See JLS 13.4.9. While it does not explicitly require that constants are inlined by the compiler, it hints that conditional compilation and support for constants in switch statements cause the compiler to always inline constants.

It looks like you're coding your own version of the capability built into enum, which does public static final for you, proper naming via name() and toString() (as well as having some other advantages, but perhaps having the disadvantage of a larger memory footprint).

Are you using an older version of Java that doesn't include enum yet?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top