Bloque estático en Java no ejecutado


class Test{
    public static void main(String arg[]){    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL);//SOP(9090);
        System.out.println(Mno.VAL+100);//SOP(9190);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}

Sé que un bloque static se ejecuta cuando se carga la clase. Pero en este caso la variable de instancia dentro de la clase Mno es final, debido a que el bloque static no se está ejecutando.

¿Por qué es así? Y si quitara el final, ¿funcionaría bien?

¿Qué memoria se asignará primero, la variable static final o el bloque static?

Si debido al modificador de acceso final la clase no se carga, entonces ¿cómo puede la variable obtener memoria?

Author: A.H., 2013-05-31

5 answers

  1. Un campo static final int es una constante en tiempo de compilación y su valor está codificado en la clase de destino sin una referencia a su origen;
  2. por lo tanto, su clase principal no activa la carga de la clase que contiene el campo;
  3. por lo tanto, el inicializador estático en esa clase no se ejecuta.

En detalle específico, el bytecode compilado corresponde a esto:

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

Tan pronto como elimine final, ya no es un tiempo de compilación constante y el comportamiento especial descrito anteriormente no se aplica. La clase Mno se carga como se espera y se ejecuta su inicializador estático.

 130
Author: Marko Topolnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 11:49:49

La razón por la que la clase no se carga es que VAL es final Y se inicializa con una expresión constante (9090). Si, y solo si, se cumplen esas dos condiciones, la constante se evalúa en tiempo de compilación y se "codifica" cuando es necesario.

Para evitar que la expresión sea evaluada en tiempo de compilación (y para hacer que la JVM cargue su clase), puede:

  • Eliminar la palabra clave final:

    static int VAL = 9090; //not a constant variable any more
    
  • O cambiar el derecho expresión del lado de la mano a algo no constante (incluso si la variable sigue siendo final):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    
 8
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-05 03:23:41

Si ves generado bytecode usando javap -v Test.class, main() sale como:

public static void main(java.lang.String[]) throws java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        26: return        

Se puede ver claramente en "11: sipush 9090" que el valor final estático se utiliza directamente, porque Mno.VAL es una constante de tiempo de compilación. Por lo tanto, no es necesario cargar la clase Mno. Por lo tanto, el bloque estático de Mno no se ejecuta.

Puede ejecutar el bloque estático cargando manualmente Mno de la siguiente manera:

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
 5
Author: Xolve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-05 19:05:25

1) En realidad no tiene extiende esa clase Mno por lo que cuando se inicia la compilación generará constante de variable VAL y cuando se inicia la ejecución cuando esa variable es necesaria su carga desde memory.so no se requiere su referencia de clase para que static bock no se ejecute.

2)si una clase extiende esa clase Mno en ese momento, ese bloque estático se incluye en Una clase. por ejemplo.. la clase pública A extiende Mno {

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(Mno.VAL);//SOP(9090);
    System.out.println(Mno.VAL+100);//SOP(9190);
}

}

class Mno{
      final static int VAL=9090;
    static`{`
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
 1
Author: Ketan_Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-06 05:30:25

Por lo que sé, se ejecutará en orden de aparición. Por ejemplo :

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

Se imprimirá

  trace init1
  trace middle
  trace init2

Acabo de probarlo y las estadísticas se inicializan (=> print) cuando la clase "Statique" se usa y se "ejecuta" en otra pieza de código (en mi caso hice "new Statique()".

 0
Author: Fabyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 09:23:47