Java é garantido para constantes sequenciais se elas puderem ser determinadas em tempo de compilation?

Considere este caso:

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

Normalmente você esperaria que o compilador inline as constantes ONE e TWO. No entanto, esse comportamento é garantido? Você pode implantar em tempo de execução Class2 sem Class1 no classpath, e esperar que ele funcione independentemente de compiladores, ou isso é uma otimização de compilador opcional?

EDIT: Por que diabos isso? Bem, eu tenho uma constante que seria compartilhada entre duas extremidades de um aplicativo (cliente e servidor sobre RMI) e seria muito conveniente, neste caso específico, colocar a constante em uma class que só pode estar em um lado dessa divisão ( como é logicamente aquele que possui esse valor constante) em vez de tê-lo em uma class de constantes arbitrárias apenas porque ele precisa ser compartilhado por ambos os lados do código. Em tempo de compilation é tudo um conjunto de arquivos de origem, mas no momento da compilation ele é dividido por pacote.

É garantido que será tratado como uma expressão constante e garantido que será internado pela seção 15.28 do JLS :

Uma expressão constante em tempo de compilation é uma expressão denotando um valor de tipo primitivo ou uma String que não é concluída abruptamente e é composta usando apenas o seguinte:

  • Literais do tipo primitivo e literais do tipo String (§3.10.5)
  • Casts para tipos primitivos e conversões para digitar String
  • Os operadores unários +, -, ~ e! (mas não ++ ou -)
  • Os operadores multiplicativos *, / e%
  • Os operadores aditivos + e –

As constantes de tempo de compilation do tipo String são sempre “internadas” para compartilhar instâncias exclusivas, usando o método String.intern.

Agora, isso não diz que é garantido que esteja embutido. No entanto, a seção 13.1 da especificação diz:

Referências a campos que são variables ​​constantes (§4.12.4) são resolvidas em tempo de compilation para o valor constante que é denotado. Nenhuma referência a tal campo constante deve estar presente no código em um arquivo binário (exceto na class ou interface que contém o campo constante, que terá código para inicializá-lo), e tais campos constantes sempre devem ter sido inicializados; o valor inicial padrão para o tipo de tal campo nunca deve ser observado.

Em outras palavras, mesmo se a expressão em si não fosse uma constante , não deveria haver referência a Class1 . Então sim, você está bem. Isso não garante necessariamente que o valor concatenado seja usado no bytecode, mas os bits referenciados anteriormente garantem que o valor concatenado esteja internado, por isso eu ficaria extremamente surpreso se não fosse apenas embutir o valor concatenado. Mesmo que isso não aconteça, você tem a garantia de que funcionará sem o Class1 .

Compilar isso com o javac 1.6.0_14 produz o seguinte 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 

Portanto, as cadeias são concatenadas em tempo de compilation e o resultado é incluído no conjunto constante de Class2.

Ele não será embutido pelo compilador, mas pelo interpretador em tempo de execução e, se possível, convertido em código assembly.

Não pode ser garantido, porque nem todos os intérpretes (JVMs) funcionam da mesma maneira. Mas as implementações mais importantes servirão.

Infelizmente eu não tenho um link para sustentar isso 🙁

Suspeito, mas não sei ao certo, que isso funcionará, mas não parece uma boa ideia.

As maneiras “normais” de fazer isso são:

  1. Coloque as constantes em um pacote compartilhado entre o cliente e o servidor. Presumivelmente, existe tal pacote, porque é onde as interfaces vão.
  2. Se não houver tal pacote, crie 2 classs com as constantes compartilhadas: uma para o servidor e outra para o cliente.

Veja JLS 13.4.9 . Embora não exija explicitamente que as constantes sejam embutidas pelo compilador, ele sugere que a compilation condicional e o suporte a constantes nas instruções switch fazem com que o compilador sempre mantenha as constantes sequenciais.

Parece que você está codificando sua própria versão da capacidade construída em enum , que faz a public static final para você, nomeando corretamente por name() e toString() (além de ter algumas outras vantagens, mas talvez ter a desvantagem de uma pegada de memory maior).

Você está usando uma versão mais antiga do Java que ainda não inclui o enum?