Método de llamada desde el constructor

Disculpe cualquier error de syntax menor o lo que sea, estoy experimentando esto con un módulo de Jitsi y no estoy muy familiarizado con Java. Quiero confirmar lo que está sucediendo y por qué y cómo debería solucionarse.

public abstract class A { public A() { this.load(); } protected void load() { } } public class B extends A { private String testString = null; public B() { super(); } @Override protected void load() { testString = "test"; } } 

La aplicación está haciendo esto al crear una instancia de la clase B utilizando un método de clase de carga por nombre:

  • Llamadas carga anulada () en la clase B
  • Inicializa las variables (llamadas “private string testString = null” de acuerdo con el depurador), anulándolas.

¿Se espera este comportamiento de Java? Que podria causar esto? Es una aplicación Java 1.6 que se ejecuta en el 1.7 JDK.

¿Se espera este comportamiento de Java?

Sí.

Que podria causar esto?

Su invocación del método reemplazado final en el constructor de clase superior no final.

Veamos lo que sucede paso a paso:

  • Usted crea una instancia de B
  • B() llama al constructor de superclase – A() , para inicializar los miembros de superclase.
  • A() invoca ahora un método no final que se anula en la clase B , como parte de la inicialización.
  • Como la instancia en el contexto es de clase B , el método load() invocado es de clase B
  • load() inicializa el campo de instancia de clase BtestString .
  • El constructor de la superclase finaliza el trabajo y lo devuelve (suponiendo que se ha terminado el encadenamiento del constructor hasta la clase Object )
  • El constructor B() comienza a ejecutar más, inicializando su propio miembro.
  • Ahora, como parte del proceso de inicialización, B sobrescribe el valor escrito anterior en testString y lo reinicializa a null .

Moraleja: Nunca llame a un método público no final de una clase no final en su constructor.

Este es un patrón de problema común con la inicialización en construcción, y se puede encontrar con frecuencia en el código de infraestructura y los DAO caseros.

La asignación a ‘nulo’ no es necesaria y puede eliminarse.

Si eso no es suficiente como un parche rápido, entonces: mueva todo el init de postconstrucción a un método separado, y envuélvalo todo en un pseudoconstructor de “método estático”.

Y si está haciendo cosas DAO, es realmente bueno distinguir entre “cargar” y “crear”, ya que estas son instancias completamente diferentes. Defina métodos independientes de “constructor estático” y quizás inits internos separados, para estos.

 abstract public class A { protected void initAfterCreate() {} } public class B { @Override protected void initAfterCreate() { this.testString = "test"; } // static constructors; // -- static public B createB() { B result = new B(); result.initAfterCreate(); } } 

Demostrar carga / crear separación para un DAO:

 public class Order { protected int id; protected boolean dbExists; static public load (int id) { Order result = new Order( id, true); // populate from SQL query.. return result; } static public create() { // allocate a key. int id = KeyAlloc.allocate( "Order"); Order result = new Order( id, false); } // internal constructor; not for external access. // protected Order (int id, boolean dbExists) { this.id = id; this.dbExists = dbExists; } }