metodos - Declaraciones estáticas finales de Java en clases de métodos locales.
public static java (3)
Considere la definición de una expresión constante en tiempo de compilación de 15.28 :
Una expresión constante de tiempo de compilación es una expresión que denota un valor de tipo primitivo o una cadena que no se completa de forma abrupta y se compone utilizando solo lo siguiente:
- Literales de tipo primitivo y literales de tipo
String
(§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5)- Conversión a tipos primitivos y conversión a tipo
String
(§15.16)- Los operadores unarios
+
,-
,~
, y!
(pero no++
o--
) (§15.15.3, §15.15.4, §15.15.5, §15.15.6)- Los operadores multiplicativos
*
,/
y%
(§15.17)- Los operadores aditivos
+
y-
(§15.18)- Los operadores de cambio
<<
,>>
y>>>
(§15.19)- Los operadores relacionales
<
,<=
,>
y>=
(pero noinstanceof
) (§15.20)- Los operadores de igualdad
==
y!=
(§15.21)- Los operadores binarios y lógicos
&
,^
, y|
(§15.22)- El condicional y el operador
&&
y el condicional u operador||
(§15.23, §15.24)- ¿El operador condicional ternario
? :
? :
(§15.25)- Expresiones entre paréntesis (§15.8.5) cuya expresión contenida es una expresión constante.
- Nombres simples (§6.5.6.1) que se refieren a variables constantes (§4.12.4).
- Nombres calificados (§6.5.6.2) de la forma TypeName. Identificador que hace referencia a variables constantes (§4.12.4).
Siguiendo la definición de una expresión constante de tiempo de compilación , tenemos 4.12.4 :
Una variable de tipo primitivo o tipo
String
, que esfinal
e inicializa con una expresión de constante de compilación (§15.28), se denomina variable constante.
Finalmente, desde 8.1.3 :
Las clases internas no pueden declarar miembros estáticos, a menos que sean variables constantes (§4.12.4), o se produzca un error en tiempo de compilación.
Al declarar una clase interna local dentro de un método, ¿por qué es legal incluir cadenas o instrucciones estáticas finales pero no es legal incluir otros objetos?
Por ejemplo:
class Outer {
void aMethod() {
class Inner {
final static String name = "compiles";
final static int ctr = 10; // compiles
final static Integer intThree = Integer.valueOf(3); // does not compile!
final static obj objConst = new Object(); // does not compile!
}
Inner inner = new Inner();
}
}
Cuando compilo esto, obtengo lo siguiente:
InnerExample.java:6: inner classes cannot have static declarations
final static Integer outer = Integer.valueOf(3);
^
InnerExample.java:7: inner classes cannot have static declarations
final static Object objConst = new Object();
^
¿Por qué la distinción? ¿Es porque la cuerda es inmutable? Si es así, ¿no sería válido también Integer.valueOf ()?
Esto se debe a que los primeros dos miembros estáticos se asignan a constantes en tiempo de compilación de tipo primitivo o tipo String.
De la Especificación del lenguaje Java, sección 8.1.3 :
8.1.3. Clases internas e instancias adjuntas
Las clases internas no pueden declarar miembros estáticos, a menos que sean variables constantes (§4.12.4), o se produzca un error en tiempo de compilación.
Y a partir de la 4.12.4 :
Una variable de tipo primitivo o tipo String, que es final e inicializa con una expresión de constante de compilación (§15.28), se denomina variable constante.
EDITAR:
Me pareció sorprendente al principio. Pensándolo más, una ventaja de esta limitación es que no hay que preocuparse cuando se inicializan los miembros estáticos de las clases internas. Puede mover una clase interna en su clase contenedora, sin preocuparse de que los valores de sus miembros estáticos se modifiquen.
Más sobre la respuesta anterior. El compilador debe demostrar que el valor asignado es una constante. El compilador de Java conoce la semántica de los tipos básicos (int, float, etc.) y la clase java.lang.String, pero no otras clases. Esto es puede entender la constancia de los dos primeros ejemplos.
El compilador no entiende que Integer.valueOf (3) también es (efectivamente) un valor constante (en realidad no es constante, pero siempre es el mismo) aunque un humano, que sabe cómo funciona la clase Integer, lo sabe. El compilador trata esto como si fuera Integer.valueOf (x) lo que puede cambiar. Sería bueno si Java ofreciera una anotación, como @interface Consistent, que declarara el comportamiento del método como estable para cualquier parámetro dado, como:
En la clase Integer: @Consistent public Entero valueOf (int x) {...}
final estático Integer intThree = Integer.valueOf (3); // ahora compila!
Eso indica que el método devuelve el mismo objeto o el mismo en cada invocación dados los mismos valores de argumento. Dado que el argumento es una expresión constante, el compilador puede deducir que el resultado será el mismo / igual en todos los usos y, por lo tanto, se puede tratar como una constante. En este caso, Integer devuelve el mismo objeto, pero puede devolver un objeto diferente (pero igual) para valores de entrada mucho más grandes (es decir, almacena valores cercanos a 0).
Tenga en cuenta que "nuevo" siempre devuelve un objeto diferente. Para el nuevo objeto () siempre es un objeto que no es igual a ningún otro objeto.