Constantes e variables ​​de tempo de compilation

A documentação da linguagem Java diz:

Se um tipo primitivo ou uma cadeia de caractere for definido como uma constante e o valor for conhecido em tempo de compilation, o compilador replaceá o nome da constante em todo o código pelo seu valor. Isso é chamado de constante de tempo de compilation.

Meu entendimento é se temos um pedaço de código:

private final int x = 10; 

Então, o compilador irá replace cada ocorrência de x no código com o literal 10 .


Mas suponha que a constante seja inicializada em tempo de execução:

 private final int x = getX(); // here getX() returns an integer value at run-time. 

Haverá alguma queda de desempenho (por mais insignificante que seja) em comparação com a constante de tempo de compilation?


Outra questão é se a linha de código abaixo:

 private int y = 10; // here y is not final 

é tratado da mesma forma que a constante de tempo de compilation pelo compilador?


Finalmente, o que eu entendo das respostas são:

  1. final static significa constante de tempo de compilation
  2. apenas final significa que é uma constante, mas é inicializado em tempo de execução
  3. apenas meios static inicializados em tempo de execução
  4. sem final é uma variável e não seria tratado como constante.

Meu entendimento é correto?

A constante de tempo de compilation deve ser:

  • declarado final
  • primitivo ou string
  • inicializado dentro da declaração
  • inicializado com expressão constante

private final int x = getX(); não é constante.

Para a segunda questão private int y = 10; não é constante (não final neste caso), portanto, o otimizador não pode ter certeza de que o valor não mudaria no futuro. Por isso, não pode otimizá-lo tão bem quanto o valor constante. A resposta é: Não, não é tratado da mesma forma que a constante de tempo de compilation.

A palavra-chave final significa que uma variável será inicializada uma vez e apenas uma vez. Uma constante real também precisa ser declarada static . Portanto, nenhum dos seus exemplos são tratados como constantes pelo compilador. No entanto, a palavra final diz a você (e ao compilador) que suas variables ​​serão inicializadas apenas uma vez (no construtor ou literalmente). Se você precisar que seus valores sejam atribuídos em tempo de compilation, seus campos devem ser estáticos.

O desempenho não é realmente afetado, mas tenha em mente que os tipos primitivos são imutáveis, depois de criar um, ele manterá esse valor na memory até que o coletor de lixo o remova. Então, se você tem uma variável y = 1; e então você muda para y = 2; na memory, a JVM terá os dois valores, mas sua variável “apontará” para a segunda.

privado int y = 10; // aqui y não é final

é tratado da mesma forma que a constante de tempo de compilation pelo compilador?

Não. Esta é uma variável de instância, criada, inicializada e usada em tempo de execução.

Pode haver uma queda de desempenho muito pequena em algumas máquinas para private final int x = getX(); já que isso envolveria pelo menos uma chamada de método (além do fato de que esta não é uma constante de tempo de compilation), mas como você disse, seria insignificante, então por que incomodar?

Quanto à segunda pergunta: y não é final e, portanto, não é uma constante de tempo de compilation, uma vez que pode mudar em tempo de execução.

private final int x = getX(); Será chamado na primeira vez que seu object for declarado. O desempenho “drop” dependerá de getX() mas esse não é o tipo de coisa para criar algum gargalo.

De acordo com o JLS, não há exigência de que “variável constante” seja estática.

Então, “variável constante”, talvez estática ou não estática (variável de instância).

Mas o JLS impõe alguns outros requisitos para que uma variável seja uma “variável constante” (além de ser apenas final):

  • sendo apenas String ou primitivo
  • inicializado apenas em linha, porque é final e final em branco não é permitido
  • inicializado com “expressão constante” = “expressão constante em tempo de compilation” (veja a citação JLS abaixo)

4.12.4. Variáveis ​​finais (JLS)

Uma variável constante é uma variável final do tipo primitivo ou tipo String que é inicializada com uma expressão constante (§15.28) .

15,28. Expressões Constantes

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.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)

Transmite para tipos primitivos e lança para digitar String (§15.16)

Os operadores unários +, -, ~ e! (mas não ++ ou -) (§15.15.3, §15.15.4, §15.15.5, §15.15.6)

Os operadores multiplicativos *, / e% (§15.17)

Os operadores aditivos + e – (§15.18)

Os operadores de turnos <<, >> e >>> (§15.19)

Os operadores relacionais <, <=,> e> = (mas não instanceof) (§15.20)

Os operadores de igualdade == e! = (§15.21)

Os operadores bit a bit e lógicos &, ^ e | (§15.22)

O operador condicional-e && e o operador condicional-ou || (§15.23, §15.24)

O operador condicional ternário? : (§15.25)

Expressões parênteses (§15.8.5) cuja expressão contida é uma expressão constante.

Nomes simples (§6.5.6.1) que se referem a variables ​​constantes (§4.12.4).

Nomes qualificados (§6.5.6.2) do formulário TypeName. Identificador que se refere a variables ​​constantes (§4.12.4).

O JLS faz as seguintes distinções entre variables final e constantes:

variables final

Uma variável pode ser declarada final . Uma variável final só pode ser atribuída a uma vez. É um erro em tempo de compilation se uma variável final é atribuída a menos que seja definitivamente não atribuída imediatamente antes da atribuição ( §16 (Definite Assignment) ).

Uma vez que uma variável final tenha sido atribuída, ela sempre contém o mesmo valor. Se uma variável final contém uma referência a um object, o estado do object pode ser alterado por operações no object, mas a variável sempre se referirá ao mesmo object. Isso se aplica também a matrizes, porque matrizes são objects; se uma variável final tiver uma referência a uma matriz, os componentes da matriz poderão ser alterados pelas operações na matriz, mas a variável sempre se referirá à mesma matriz.

Uma final branco é uma variável final cuja declaração não possui um inicializador.

constantes

Uma variável constante é uma variável final do tipo primitivo ou tipo String que é inicializada com uma expressão constante ( §15.28 ).

A partir dessa definição, podemos discernir que uma constante deve ser:

  • declarado final
  • de tipo primitivo ou tipo String
  • inicializado dentro de sua declaração (não uma final branco )
  • inicializado com uma expressão constante

E quanto às constantes de tempo de compilation?

O JLS não contém a frase constante de tempo de compilation . No entanto, os programadores costumam usar os termos tempo de compilation constante e constante de maneira intercambiável.

Se uma variável final não atender aos critérios descritos acima para ser considerada uma constante, ela deve ser tecnicamente referida como uma variável final .

Cada literal primitivo e literal de cadeia é uma constante de tempo de compilation.

Consulte: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28

    Intereting Posts