2011-12-15 7 views
16

Considere el siguiente fragmento de código en Java. No compilaráLos miembros de clase no inicializados en Java no emiten ningún error de compilación. las variables locales sin embargo lo hacen. ¿Por qué?

package temppkg; 

final public class Main 
{ 
    private String x; 
    private int y; 

    private void show() 
    { 
     String z; 
     int a; 

     System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error. 
     System.out.println(y); // Works fine displaying its default value which is zero. 
     System.out.println(z.toString()); // Causes a compile-time error - variable z might not have been initialized. 
     System.out.println(a); // Causes a compile-time error - variable a might not have been initialized. 
    } 

    public static void main(String []args) 
    { 
     new Main().show(); 
    } 
} 

¿Por qué los miembros de la clase (x e y) declaradas en el código anterior no emite ningún error en tiempo de compilación a pesar de que no se inicializan de manera explícita y sólo se requieren las variables locales para ser inicializado?

+4

+1 Esta resultó ser una muy buena pregunta. Me sorprende cuántos programadores de Java no saben que los miembros de la clase se inicializan cuando se crean. – Paul

+1

Tal vez la pregunta debería ser "¿por qué el compilador inicializa miembros con valores predeterminados, pero no variables locales". Estoy de acuerdo en que no es muy intuitivo que en su ejemplo, 'x' se inicializa a' nulo', pero 'z' no lo es. Incluso si tiene sentido, una vez que uno piensa en las razones dadas en las respuestas a continuación. – mth

+0

@ mth, en mi respuesta a continuación encontrará su respuesta. La introducción en Java Language Spec dice: "... el lenguaje de programación Java no inicializa automáticamente las variables locales para evitar el enmascaramiento de los errores de programación". – Paul

Respuesta

21

En caso de duda, compruebe la Java Language Specification (JLS).

En the introduction encontrará:

Capítulo 16 describe la forma precisa en que el lenguaje asegura que las variables locales se establecen definitivamente antes de su uso. Mientras que todas las demás variables se inicializan automáticamente a un valor predeterminado, el lenguaje de programación Java no inicializa automáticamente las variables locales para evitar el enmascaramiento de los errores de programación.

El primer párrafo de chapter 16 estados,

Cada variable local y cada campo final en blanco debe tener un valor definitivamente asignado cuando cualquier acceso de su valor se produce .... Un compilador de Java obligada lleve a cabo un análisis de flujo conservador específico para asegurarse que, para cada acceso de una variable local o campo final en blanco f, f se asigna definitivamente antes del acceso; de lo contrario, debe producirse un error en tiempo de compilación.

Los valores predeterminados están en section 4.12.5. La sección se abre con:

Cada variable de clase, variable de instancia, o componente de matriz es inicializa con un valor por defecto cuando se crea.

... y luego pasa a enumerar todos los valores predeterminados.

El JLS no es realmente tan difícil de entender y me he encontrado cada vez más usando para entender por qué Java hace lo que hace ... ¡después de todo, es la Biblia de Java!

+6

"En caso de duda, verifique la Especificación del lenguaje Java (JLS)." No creo que sea una buena sugerencia para un principiante absoluto. Un libro o algún artículo sería una mejor sugerencia. Pero la respuesta es genial. +1. –

1

Los miembros de la clase podrían haberse inicializado en otro lugar de su código, por lo que el compilador no puede ver si se inicializaron en el momento de la compilación.

+2

No. Se inicializan con valores predeterminados cuando se crea. Consulte [Java Language Spec 4.12.5] (http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.5). – Paul

+0

Creo que el downvote es un poco duro. Ver mi otro comentario. – Stefan

3

Por qué iban a emitir una advertencia de compilación ?, como variables de instancia Cadena obtendrá un valor predeterminado de null, y int obtendrá un valor predeterminado de 0.

El compilador no tiene forma de saber que x.toString(), causará una excepción de tiempo de ejecución, porque el valor de null no se establece realmente hasta después del tiempo de ejecución.

1

En general, el compilador no podía saber con certeza si un miembro de la clase se ha inicializado o no antes. Por ejemplo, podría tener un método setter que establezca el valor para un miembro de la clase y otro método que acceda a ese miembro. El compilador no puede emitir una advertencia cuando accede a esa variable porque no puede saber si se ha llamado al setter antes o no.

Acepto que en este caso (el miembro es privado y no hay un único método que escriba la variable) parece que podría generar una advertencia del compilador. Bueno, de hecho, todavía no está seguro de que la variable no se haya inicializado, ya que podría haberse accedido a través de la reflexión.

Thins son mucho más fáciles con variables locales, ya que no se puede acceder desde fuera del método, ni siquiera por reflexión (afaik, corríjanme si está mal), por lo que el compilador puede ser un poco más útil y advertirnos de variables no inicializadas

Espero que esta respuesta le ayuda :)

+1

No. Los miembros de la clase se inicializan con los valores predeterminados cuando se crean. Consulte [Java Language Spec 4.12.5] (http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.5). – Paul

+0

@Paul que luego plantearía la pregunta de por qué se inicializaron con los valores predeterminados? Y si él reemplaza el can not con could not creo que es un buen argumento. +1 – Stefan

+0

@Paul: Tiene razón en que mi redacción no es técnicamente precisa desde que se inicializaron.Sin embargo, creo que lo que a Lion le interesaba no era la especificación, sino la razón de ser de la especificación, de ahí mi explicación. De todos modos, gracias por la corrección, estoy editando mi respuesta, tal como lo sugirió Stefan para reflejar eso. – Riseven

1

Las variables de miembro se inicializan automáticamente a sus valores predeterminados cuando se construye (instancia) un objeto. Eso es cierto incluso cuando los haya inicializado manualmente, primero se inicializarán a los valores predeterminados y luego a los valores que haya proporcionado.

Esto es un poco poco largo artículo, pero lo explica: Object initialization in Java

Mientras que para las variables locales (los que se declaran dentro de un método) no se inicializa automáticamente, lo que significa que tiene que hacerlo de forma manual, incluso si quieres que tengan sus valores predeterminados.

Puede ver cuáles son los valores predeterminados para las variables con diferentes tipos de datos here.

El valor predeterminado para las variables de tipo de referencia es null. Es por eso que está lanzando NullPointerException en lo siguiente:

System.out.println(x.toString()); // Causes a NullPointerException but doesn't issue a compiler error. 

En el siguiente caso, el compilador es suficientemente inteligente para saber que la variable no se ha iniciado todavía (porque es local y no se ha inicializado), por eso problema de compilación:

System.out.println(z.toString()); // "Cuases a compile-time error - variable z might not have been initialized. 
+1

"Las variables miembro se inicializan automáticamente a sus valores locales" - ¿Qué significa eso? – Paul

+0

Significó escribir por defecto. Gracias por detectarlo. Arreglado. –

Cuestiones relacionadas