¿Está bien llamar al método abstracto desde el constructor en Java?

Supongamos que tengo una clase Base abstracta que implementa la interfaz Runnable.

public abstract class Base implements Runnable { protected int param; public Base(final int param) { System.out.println("Base constructor"); this.param = param; // I'm using this param here new Thread(this).start(); System.out.println("Derivative thread created with param " + param); } @Override abstract public void run(); } 

Y esta es una de las pocas clases derivadas.

 public class Derivative extends Base { public Derivative(final int param) { super(param); } @Override public void run() { System.out.println("Derivative is running with param " + param); } public static void main(String[] args) { Derivative thread = new Derivative(1); } } 

El punto es que quiero que mi clase Base haga algunas cosas generales en lugar de copiarlas todas las veces. En realidad, está funcionando bien, la salida es siempre la misma:

El constructor base El hilo derivado creado con param 1 El derivado se ejecuta con param 1

Pero, ¿es seguro IN JAVA iniciar un hilo llamando al método abstracto en el constructor? Porque, en C ++ y C # no es seguro en la mayoría de los casos, hasta donde yo sé. ¡Gracias!

Este código demuestra por qué nunca debes llamar a un método abstracto, o cualquier otro método invalidante, desde un constructor:

 abstract class Super { Super() { doSubStuff(); } abstract void doSubStuff(); } class Sub extends Super { String s = "Hello world"; void doSubStuff() { System.out.println(s); } } public static void main(String[] args) { new Sub(); } 

Cuando se ejecuta, esto imprime null . Esto significa que los únicos métodos “seguros” para tener en un constructor son privados y / o finales.

Por otro lado, su código en realidad no llama a un método abstracto de un constructor. En cambio, pasas un objeto no inicializado a otro hilo para su procesamiento, lo que es peor, ya que el hilo que estás iniciando puede tener prioridad y ejecutarse antes de que tu Base finalice su inicialización.

No es una buena idea, ya que cuando se invoca run (), es posible que el objeto Derivado no se haya inicializado. Si run () depende de cualquier estado en Derivative, puede fallar.

En tu caso simple, funciona. Pero entonces no tiene sentido la subclase. Puedes simplemente

 public Base(final int param, Runnable action) { new Thread(action).start(); 

Es una muy mala práctica llamar a un método abstracto de un constructor. Los métodos llamados desde los constructores siempre deben ser privados o finales, para evitar anulación.

Vea este enlace a una pregunta aquí

Pasar this fuera del constructor se llama “dejar escapar this del constructor”, y puede dar lugar a algunos errores particularmente desagradables y extraños, porque el objeto puede estar en un estado incoherente.

Este es especialmente el caso cuando this se pasa a otro hilo, como en este ejemplo. Debido al derecho de las JVM para reordenar las declaraciones dentro de un hilo, puede obtener un comportamiento / estado indefinido.