java - seleccionar - macro romper vinculos excel
¿Por qué dos programas tienen errores de referencia directa mientras que el tercero no? (4)
Lo siguiente no se compila, dando un mensaje de "referencia directa ilegal":
class StaticInitialisation {
static
{
System.out.println("Test string is: " + testString);
}
private static String testString;
public static void main(String args[]) {
new StaticInitialisation();
}
}
Sin embargo, lo siguiente sí se compila:
class InstanceInitialisation1 {
{
System.out.println("Test string is: " + this.testString);
}
private String testString;
public static void main(String args[]) {
new InstanceInitialisation1();
}
}
Pero lo siguiente no se compila, dando un mensaje de "referencia directa ilegal":
class InstanceInitialisation2 {
private String testString1;
{
testString1 = testString2;
}
private String testString2;
public static void main(String args[]) {
new InstanceInitialisation2();
}
}
¿Por qué StaticInitialisation e InstanceInitialisation2 no se compilan, mientras que InstanceInitialisation1 sí?
Aquí lo que tenemos que entender es que en el segundo fragmento de código está usando el bloque y esta palabra clave .
- El bloque se ejecuta si se crea el objeto.
- Eso significa que el objeto se crea en el área del montón.
- Está utilizando externamente esta palabra clave para obtener un valor de variable de instancia.
- Aquí el objeto creado con valores predeterminados que devolverá como valor.
- Sin usar esta palabra clave, no puede compilar el segundo fragmento también.
Esto está cubierto por la sección 8.3.3 de la JLS:
El uso de variables de clase cuyas declaraciones aparecen textualmente después del uso a veces está restringido, a pesar de que estas variables de clase están dentro del alcance (§6.3). Específicamente, es un error en tiempo de compilación si se cumple todo lo siguiente:
La declaración de una variable de clase en una clase o interfaz C aparece textualmente después de un uso de la variable de clase;
El uso es un nombre simple en un inicializador variable de clase de C o un inicializador estático de C;
El uso no está en el lado izquierdo de una tarea;
C es la clase o interfaz más interna que encierra el uso.
El uso de variables de instancia cuyas declaraciones aparecen textualmente después del uso a veces está restringido, a pesar de que estas variables de instancia están dentro del alcance. Específicamente, es un error en tiempo de compilación si se cumple todo lo siguiente:
La declaración de una variable de instancia en una clase o interfaz C aparece textualmente después de un uso de la variable de instancia;
El uso es un nombre simple en un inicializador de variable de instancia de C o un inicializador de instancia de C;
El uso no está en el lado izquierdo de una tarea;
C es la clase o interfaz más interna que encierra el uso.
En su segundo caso, el uso no es un nombre simple: lo tiene explícitamente. Eso significa que no cumple con la segunda viñeta en la segunda lista citada anteriormente, por lo que no hay error.
Si lo cambia a:
System.out.println("Test string is: " + testString);
... entonces no se compilará.
O en la dirección opuesta, puede cambiar el código en el bloque inicializador estático a:
System.out.println("Test string is: " + StaticInitialisation.testString);
Extraño, pero así son las cosas.
Razón simple: es demasiado costoso o imposible de analizar y prohíbe todas las referencias directas. p.ej
{
print( getX(); ); // this.x
print( that().x ); // this.x
}
int x;
int getX(){ return x; }
This that(){ return this; }
La especificación establece la prohibición de algunos casos simples indicativos de errores comunes del programador.
Ver también ¿El inicializador recursivo funciona cuando agrego "esto"?
Veamos estos dos ejemplos, supongo que esto te dejará claro.
public class InstanceAndSataticInit {
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInit.testStringStatic);
}
public static String testStringStatic="test";
public String testString="test";
public static void main(String args[]) {
new InstanceAndSataticInit();
}
}
Salida:
Test string is (static init ): null
Test string is (instance init): null
Y
public class InstanceAndSataticInitVariableFirst {
public static String testStringStatic="test";
public String testString="test";
{
System.out.println("Test string is (instance init): " + this.testString);
}
static{
System.out.println("Test string is (static init ): " + InstanceAndSataticInitVariableFirst.testStringStatic);
}
public static void main(String args[]) {
new InstanceAndSataticInitVariableFirst();
}
}
salida:
Test string is (static init ): test
Test string is (instance init): test
Entonces puedes decir que la secuencia es así.
-
La variable estática se creará pero no se inicializará.
-
La inicialización estática se ejecutará de acuerdo con la secuencia dada.
- Se creará una variable no estática pero no se inicializará.
- La inicialización no estática se ejecutará de acuerdo con la secuencia dada.
Por secuencia me refiero a la aparición en el código.
Supongo que estos pasos responden a sus
dos
ejemplos que
no funcionan
StaticInitialisation
e
InstanceInitialisation2
Pero en caso de que su
segundo ejemplo de trabajo
InstanceInitialisation1
al usar
this
palabra clave, en realidad está ayudando al compilador a pasar por alto la jerarquía textual.
Lo mismo sucede en caso de
static
cuando llamo
InstanceAndSataticInit.testStringStatic
en mi primer ejemplo
InstanceAndSataticInit