É Java garantido para as constantes string em linha se eles podem ser determinado em tempo de compilação

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

  •  05-07-2019
  •  | 
  •  

Pergunta

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 o compilador para inline os um e dois constantes. No entanto, é esse comportamento garantida? você pode implantar em tempo de execução Class2 sem Class1 no classpath, e esperar que ele funcione independentemente de compiladores, ou isto é uma optimização do compilador opcional?

EDIT: Por que diabos fazer isso? Bem, eu tenho uma constante que seria compartilhado entre duas extremidades de uma aplicação (cliente e servidor através de RMI) e seria muito conveniente neste caso em particular para colocar a constante sobre uma classe que só pode ser de um lado dessa divisão ( como é logicamente a que possui esse valor constante) em vez de tê-lo em uma classe de constantes arbitrárias só porque ele precisa ser compartilhado por ambos os lados do código. Em tempo de compilação é tudo um conjunto de arquivos de origem, mas em tempo de compilação é dividido por pacote.

Foi útil?

Solução

É garantido para ser tratado como uma expressão constante, e garantido para ser internado por seção 15.28 dos JLS :

A expressão constante de tempo de compilação é uma expressão denotando um valor de tipo primitivo ou uma corda que faz não completa abruptamente e é composto usando apenas o seguinte:

  • literais de tipo primitivo e literais de tipo corda (§3.10.5)
  • moldes para tipos primitivos e moldes para o tipo string
  • Os operadores unários +, -, ~, e! (Mas não ++ ou -)
  • Os operadores multiplicativos *, / e%
  • Os operadores aditivos + e -
  • ...

...

tempo de compilação constantes do tipo String são sempre "internado", de modo a compartilhar instâncias únicas, utilizando o método String.intern.

Agora, isso não chega a dizer que está garantido para ser embutido. No entanto, a seção 13.1 da especificação diz:

As referências aos campos que são constantes variáveis ??(§4.12.4) são resolvidas em tempo de compilação para o valor constante que é indicado. Nenhuma referência a tais um domínio constante deve estar presente em o código em um arquivo binário (exceto em a classe ou interface contendo o campo constante, que terá código para inicializar-lo), e constante tal campos devem sempre parecem ter sido inicializado; o valor inicial padrão para o tipo de tal obrigação campo de um Nunca ser observadas.

Em outras palavras, , mesmo se a própria expressão não eram uma constante , não deve haver nenhuma referência a Class1. Então, sim, você está bem. Isso não necessariamente garantia de que o valor concatenado é usado no bytecode, mas os bits referenciados garantia anteriormente que o valor concatenado está internada, então eu ficaria imensamente surpreendeu se não apenas inline valor concatenado. Mesmo se isso não acontecer, você tem a garantia de que ele vai trabalhar sem Class1.

Outras dicas

Compilando que, com 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

Assim, as cordas são concatenados em tempo de compilação e o resultado está incluído na piscina constante de Class2.

Não vai ser embutido pelo compilador, mas pelo intérprete em tempo de execução e, se possível convertido para código de montagem.

Ele não pode ser garantida, porque nem todos os intérpretes de trabalho (JVM) da mesma maneira. Mas a maioria das implementações importantes vai fazer.

Infelizmente eu não tenho um link para sustentar este :(

Eu suspeito, mas não sei ao certo, que este trabalho, mas não soa como uma boa idéia.

As formas "normais" de fazer isso são:

  1. Coloque as constantes em um pacote que é compartilhada entre o cliente eo servidor. Presumivelmente, não há tal pacote um, porque é onde as interfaces ir.
  2. Se não há tal pacote, criar 2 classes com as constantes compartilhados: uma para o servidor e outro para o cliente.

Consulte JLS 13.4.9 . Enquanto ele não exige explicitamente que as constantes são inlined pelo compilador, ele sugere que a compilação condicional e suporte para constantes nas demonstrações switch fazer com que o compilador para constantes sempre inline.

Parece que você está programando a sua própria versão da capacidade incorporada para enum, que faz public static final para você, nomenclatura adequada via name() e toString() (bem como ter algumas outras vantagens, mas talvez tendo a desvantagem de uma memória maior footprint).

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top