2010-02-02 16 views

Respuesta

23

Las variables de instancia y de clase se inicializan en nulo (o 0), pero las variables locales no lo son.

Ver §4.12.5 del JLS para una explicación muy detallada que dice básicamente lo mismo:

Every variable in a program must have a value before its value is used:

  • Each class variable, instance variable, or array component is initialized with a default value when it is created:
    • [snipped out list of all default values]
  • Each method parameter is initialized to the corresponding argument value provided by the invoker of the method.
  • Each constructor parameter is initialized to the corresponding argument value provided by a class instance creation expression or explicit constructor invocation.
  • An exception-handler parameter is initialized to the thrown object representing the exception.
  • A local variable must be explicitly given a value before it is used, by either initialization or assignment, in a way that can be verified by the compiler using the rules for definite assignment.
+1

¿Por qué se tomó esta decisión? ¿Por qué no simplemente los inicias en 'null' como variables de clase? –

+0

Quizás para un mejor código/legibilidad? –

+0

Hay muchas preguntas de stackoverflow sobre por qué las variables locales no tienen valores predeterminados. p.ej. http://stackoverflow.com/questions/415687/why-are-local-variables-not-initialized-in-java –

7

Se debe a que Java está siendo muy útil (lo más posible).

Utilizará esta misma lógica para atrapar algunos casos extremos muy interesantes que podría haber pasado por alto. Por ejemplo:

int x; 

if(cond2) 
    x=2; 
else if(cond3) 
    x=3; 

System.out.println("X was:"+x); 

Esto fallará porque había un caso más que no se especificó. El hecho es que un caso else aquí debe ser absolutamente especificado, incluso si es solo un error (Lo mismo es cierto de una condición predeterminada: en una instrucción switch).

Lo que debe sacarse de esto, curiosamente, es no inicializar sus variables locales hasta que descubra que realmente tiene que hacerlo. Si tiene el hábito de decir siempre "int x = 0"; evitará que este fantástico detector de "mala lógica" funcione. Este error me ha ahorrado tiempo más de una vez.

4

Ditto en Bill K. agrego:

El compilador de Java puede proteger de lastimarse a sí mismo al no establecer una variable antes de usarla dentro de una función. Por lo tanto, explícitamente NO establece un valor predeterminado, como lo describe Bill K.

Pero cuando se trata de variables de clase, sería muy difícil para el compilador hacer esto por usted. Una variable de clase podría ser establecida por cualquier función en la clase. Sería muy difícil para el compilador determinar todas las órdenes posibles en las que se podrían llamar las funciones. Por lo menos, tendría que analizar todas las clases en el sistema que llaman a cualquier función en esta clase. Bien podría tener que examinar los contenidos de cualquier archivo de datos o base de datos y de alguna manera predecir qué entradas harán los usuarios. En el mejor de los casos, la tarea sería extremadamente compleja, en el peor imposible. Entonces, para las variables de clase, tiene sentido proporcionar un valor predeterminado confiable. Ese valor predeterminado es, básicamente, llenar el campo con bits de cero, por lo que obtienes nulo para referencias, cero para enteros, falso para booleanos, etc.

Como dice Bill, definitivamente NO debes tener el hábito de automáticamente inicializando variables cuando las declaras. Solo inicialice las variables en el momento de la declaración si esto realmente tiene sentido en el contexto de su programa. Por ejemplo, si el 99% del tiempo desea que x sea 42, pero dentro de alguna condición IF, puede descubrir que este es un caso especial y x debería ser 666, entonces está bien, comience con "int x = 42;" y dentro del IF anula esto. Pero en el caso más normal, donde se calcula el valor según las condiciones, no se inicialice en un número arbitrario. Simplemente llénelo con el valor calculado.Entonces, si comete un error de lógica y no puede establecer un valor bajo una combinación de condiciones, el compilador puede decirle que ha cometido un error en lugar del usuario.

PS He visto una gran cantidad de programas de hoja de metal que dicen cosas como:

HashMap myMap=new HashMap(); 
myMap=getBunchOfData(); 

Por qué crear un objeto para inicializar la variable cuando se sabe que se va rápidamente a lanzar este objeto fuera una milésima de segundo más tarde? Eso es solo una pérdida de tiempo.

Editar

Para tomar un ejemplo trivial, supongamos que escribió esto:

int foo; 
if (bar<0) 
    foo=1; 
else if (bar>0) 
    foo=2; 
processSomething(foo); 

Esto generará un error en tiempo de compilación, porque el compilador dará cuenta de que cuando la barra == 0, nunca pones foo, pero luego tratas de usarlo.

Pero si inicializar foo a un valor ficticio, como

int foo=0; 
if (bar<0) 
    foo=1; 
else if (bar>0) 
    foo=2; 
processSomething(foo); 

A continuación, el compilador ver que no importa cuál es el valor de la barra, foo se establece en algo, por lo que no va a producir un error. Si lo que realmente quieres es que foo sea 0 cuando la barra es 0, entonces está bien. Pero si lo que realmente sucedió es que quisiste decir que una de las pruebas es < = o> = o si quisiste incluir una última cosa para cuando bar == 0, entonces has engañado al compilador para que no detecte tu error. Y, por cierto, así es como creo que una construcción así es un pobre estilo de codificación: el compilador no solo no está seguro de lo que pretendía, sino que tampoco puede hacerlo un programador de mantenimiento en el futuro.

+0

¿Por qué no simplemente inicializarlo a nulo? El único caso problemático real en el que puedo pensar es cuando debes declarar una variable final que debe establecerse como un valor en un bloque try. Pero puede definir una variable temporal aquí y asignarle su valor después del bloque try a uno final. – sibidiba

+0

@sibidiba: ¿A qué parte de mi respuesta está respondiendo? Si quiere decir en general, perdería la ventaja de la verificación en tiempo de compilación. Ver la respuesta de Bill K. Si se refiere a mi comentario de cierre con el ejemplo myMap, entonces la solución más fácil es escribir "HashMap myMap = getBunchOfData()" y omitir el objeto adicional sin sentido. – Jay

1

Me gusta el punto de Bill K acerca de dejar que el compilador trabaje para usted: me había acostumbrado a inicializar cada variable automática porque 'parecía lo que Java debía hacer'. No comprendí que las variables de clase (es decir, las cosas persistentes de las que se preocupan los constructores) y las variables automáticas (algunos contadores, etc.) son diferentes, a pesar de que TODO es una clase en Java.

así que volví y se elimina la inicialización que estaría utilizando, por ejemplo

List <Thing> somethings = new List<Thing>(); 
somethings.add(somethingElse); // <--- this is completely unnecessary 

Niza. Había estado recibiendo una advertencia del compilador para

List<Thing> somethings = new List(); 

y que había pensado que el problema era la falta de inicialización. INCORRECTO. El problema era que no había entendido las reglas y necesitaba el <Thing> identificado en el "nuevo", no había ningún elemento real del tipo <Thing> creado.

(Siguiente Tengo que aprender cómo poner literal menor que y mayor que las indicaciones en HTML!)

+0

@Bill IV Yo limpié las citas por ti; todo lo que necesita hacer es designar las secciones de código como código (el icono 101/010 sobre el editor lo hará). –

+0

¡Gracias, Carl! –

0

No sé la lógica detrás de él, pero las variables locales no se inicializan a null. Supongo que hará tu vida más fácil. Podrían haberlo hecho con variables de clase si fuera posible. No significa que debes inicializarlo al principio. Esto está muy bien:

MyClass cls; 
if (condition) { 
    cls = something; 
else 
    cls = something_else; 
0

Claro, si realmente tiene dos líneas en la parte superior de uno al otro como show-declarará, lo llena, hay necesidad de un constructor por defecto. Pero, por ejemplo, si desea declarar algo una vez y usarlo varias o muchas veces, el constructor predeterminado o la declaración nula son relevantes.¿O es el puntero a un objeto tan liviano que es mejor asignarlo una y otra vez dentro de un bucle, porque la asignación del puntero es mucho menor que la instanciación del objeto? (Presumiblemente hay una razón válida para un nuevo objeto en cada paso del ciclo).

Cuenta IV

+0

No estoy diciendo: No cree un valor y vuelva a usarlo. Estoy diciendo: Evita completar un valor ficticio como marcador de posición hasta que encuentres el valor real. Si solo declaras la variable pero la dejas sin llenar, luego revisas todas tus IF y BUT para llenarla, y luego tratas de usarla, el compilador te dirá si hay alguna ruta posible a través de ella donde nunca la llenaste . Pero si completa un valor ficticio, el compilador no tiene forma de saber que ese es un valor ficticio y no un valor real, por lo que pierde la ventaja de la verificación en tiempo de compilación. – Jay

Cuestiones relacionadas