2009-12-10 10 views
10

Tengo algunos casos que me pregunto. En primer lugar, si usted no tiene constructor:¿Qué sucede cuando las subclases no definen un constructor en Java?

class NoCons { int x; } 

Cuando hago new NoCons(), el constructor por defecto se llama. ¿Qué hace exactamente? ¿Establece x en 0, o sucede eso en otro lugar?

Qué pasa si tengo esta situación:

class NoCons2 extends NoCons { int y; } 

¿Qué sucede cuando llamo new NoCons2()? ¿Se llama al constructor predeterminado de NoCons y luego al constructor de NoCons2? ¿Cada uno de ellos establece los campos respectivos x y y en 0?

¿Qué pasa con esta versión:

class Cons2 extends NoCons { int y; public Cons2() {} } 

Ahora tiene un constructor, pero no llama al constructor de la superclase. ¿Cómo se inicializa alguna vez el x? Lo que si tuviera esta situación:

class Cons { int x; public Cons() {} } 
class NoCons2 extends Cons { int y; } 

¿El constructor Cons ser llamado?

Podría probar todos estos ejemplos, pero no puedo decir cuándo se ejecuta un constructor predeterminado. ¿Cuál es una forma general de pensar sobre esto para saber lo que sucede en situaciones futuras?

Respuesta

13

Cuando una clase Java tiene ningún constructor definido explícitamente se añade un no-args público predeterminado constructor modo:

class Cons { int x; } 

es equivalente a:

class Cons { int x; public Cons() {} } 

el constructor de una subclase que no lo hace de forma explícita define cuál de las llamadas del constructor de su padre llamará automáticamente al constructor predeterminado en la clase primaria antes de hace cualquier otra cosa. Así que asumiendo:

class A { public A() { System.out.println("A"); } } 

entonces esto:

class B extends A { public B() { System.out.println("B"); } } 

es exactamente equivalente a:

class B extends A { public B() { super(); System.out.println("B"); } } 

y la salida en ambos casos será:

A 
B 

Así que cuando lo haces:

new NoCons2(); 

El orden es:

  1. constructor predeterminado de NoCons llama, aunque esto es técnicamente la primera parte de (2); y luego
  2. Se llama al constructor predeterminado de NoCons2.
0

cletus respondió a la pregunta más grande. La respuesta para el otro es que las variables miembro en Java se inicializan en 0, nulo o falso (dependiendo del tipo).

1

Quiere consultar el Java Language Specification section 12.5 Creation of New Class Instances para obtener las reglas oficiales de creación de objetos. La sección pertinente es:

Justo antes de una referencia al objeto recién creado se devuelve como el resultado, el constructor indicada se procesa para inicializar el nuevo objeto usando el siguiente procedimiento:

  1. Asignar los argumentos para el constructor a las variables de parámetros recién creadas para esta invocación de constructor.
  2. Si este constructor comienza con una invocación de constructor explícita de otro constructor en la misma clase (usando esto), entonces evalúe los argumentos y procese esa invocación de constructor recursivamente utilizando estos mismos cinco pasos. Si la invocación del constructor finaliza abruptamente, entonces este procedimiento se completa abruptamente por la misma razón; de lo contrario, continúe con el paso 5.
  3. Este constructor no comienza con una invocación explícita del constructor de otro constructor en la misma clase (usando esto). Si este constructor es para una clase que no sea Object, entonces este constructor comenzará con una invocación explícita o implícita de un constructor de superclase (usando super). Evalúe los argumentos y procese esa invocación de constructor de superclase recursivamente utilizando estos mismos cinco pasos. Si la invocación del constructor finaliza abruptamente, entonces este procedimiento se completa abruptamente por el mismo motivo. De lo contrario, continúe con el paso 4.
  4. Ejecute los inicializadores de instancia y los inicializadores de variable de instancia para esta clase, asignando los valores de los inicializadores de variable de instancia a las variables de instancia correspondientes, en el orden de izquierda a derecha en el que aparecen textualmente en el código fuente para la clase. Si la ejecución de cualquiera de estos inicializadores da como resultado una excepción, no se procesan más inicializadores y este procedimiento se completa abruptamente con la misma excepción. De lo contrario, continúe con el paso 5. (En algunas implementaciones anteriores, el compilador omitió incorrectamente el código para inicializar un campo si la expresión del inicializador de campo era una expresión constante cuyo valor era igual al valor de inicialización predeterminado para este tipo).
  5. Ejecutar el resto del cuerpo de este constructor. Si la ejecución se completa abruptamente, entonces este procedimiento se completa abruptamente por el mismo motivo. De lo contrario, este procedimiento se completa normalmente.

Así, en sus ejemplos, cuando ningún constructor se suministra en su definición de clase, se inserta el predeterminado para usted. Cuando se escribe

new NoCons2(); 
  1. Primero el super constructor se llama (se inserta una llamada a super() para usted, porque usted no hace la llamada explícita).
  2. Las variables de instancia para la clase que se está construyendo se inicializan.
  3. El resto del cuerpo del constructor se ejecuta (nada en su caso).

En su primer ejemplo, x se establecerá durante la construcción de NoCons e Y se establecerá durante la construcción de NoCons2.

Así que la secuencia exacta de los acontecimientos en ese ejemplo será algo como:

  1. NoCons2 constructor de llamada.
  2. Llamar a super(), ir a 3
  3. NoCons constructor llamado.
  4. Llamar a super(), que es una llamada implícita al Object().
  5. Pase lo que pase en el constructor de objetos.
  6. x se establece en 0.
  7. termina el cuerpo del constructor NoCons, devuelve el control al constructor NoCons2.
  8. y se establece en 0.
  9. cuerpo acabado de NoCons2 constructor
  10. NoCons2 construcción objeto completo.
0

Aquí es esencialmente lo que ocurre cuando "nueva" se llama:

  • la memoria se asigna (lo suficiente para contener todos los miembros de datos de la clase, y todas las clases de padres, y algunos información de limpieza)
  • la memoria asignada se establece en cero (lo que significa 0, 0.0, falso, nulo según el tipo)
  • se llama al constructor para la clase que está después de llamar a "nuevo".
  • más cosas suceden (que viene después de la siguiente parte)

Si usted no proporciona un constructor el compilador hace lo siguiente:

  • crea un constructor sin argumentos
  • el constructor creado tiene el mismo acceso que la clase (tan público o paquete)
  • se llama super().

Así que cuando el constructor de la clase después de la llamada "nueva" se llama la primera cosa que hace es "super()", que llama al constructor padre. Esto sucede hasta java.lang.Object.

Antes de que el cuerpo del constructor se ejecuta el VM hace lo siguiente:

  • las variables de instancia que son valores asignados se les ha dado
  • entonces el bloque ejemplo inicializador, si está presente se ejecuta.

El siguiente código muestra todo esto:

public class Main 
{ 
    private Main() 
    { 
    } 

    public static void main(final String[] args) 
    { 
     final Foo fooA; 
     final Foo fooB; 

     fooA = new Foo(7); 
     System.out.println("---------------------"); 
     fooB = new Foo(42); 
    } 
} 

class Bar 
{ 
    protected int valueA = getValue("valueA", 1); 
    protected int valueB; 

    static 
    { 
     System.out.println("static block for Bar happens only one time"); 
    } 

    { 
     System.out.println("instance block for Bar happens one time for each new Bar"); 
     System.out.println("valueA = " + valueA); 
     System.out.println("valueB = " + valueB); 
    } 

    Bar() 
    { 
     super(); // compiler adds this - you would not type it in 
     System.out.println("running Bar()"); 
     System.out.println("valueA = " + valueA); 
     System.out.println("valueB = " + valueB); 
     valueB = getValue("valueB", 2); 
    } 

    protected static int getValue(final String name, final int val) 
    { 
     System.out.println("setting " + name + " to " + val); 
     return (val); 
    } 
} 

class Foo 
    extends Bar 
{ 
    protected int valueC = getValue("valueC", 1); 
    protected int valueD; 

    static 
    { 
     System.out.println("static block for Foo happens only one time"); 
    } 

    { 
     System.out.println("instance block for Foo happens one time for each new Foo"); 
     System.out.println("valueC = " + valueC); 
     System.out.println("valueD = " + valueD); 
    } 

    Foo(final int val) 
    { 
     super(); // compiler adds this - you would not type it in 
     System.out.println("running Foo(int)"); 
     System.out.println("valueC = " + valueC); 
     System.out.println("valueD = " + valueD); 
     valueD = getValue("valueD", val); 
    } 
} 
Cuestiones relacionadas