Error de Java: el superconstructor implícito no está definido para el constructor predeterminado

89

Tengo un código Java simple que se parece a esto en su estructura:

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass(String someString) {
        super(someString);
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

Tendré bastantes subclases de BaseClass, cada una implementando el getName()método a su manera ( patrón de método de plantilla ).

Esto funciona bien, pero no me gusta tener el constructor redundante en las subclases. Es más para escribir y es difícil de mantener. Si BaseClasstuviera que cambiar la firma del método del constructor, tendría que cambiar todas las subclases.

Cuando elimino el constructor de las subclases, obtengo este error en tiempo de compilación:

Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor

¿Es posible lo que estoy tratando de hacer?

Joel
fuente
1
¡Por favor, deje el constructor 'redundante'! Mantiene la legibilidad de su código y todos los IDE modernos pueden crearlo automáticamente, por lo que solo tiene que ingresar un atajo.
Andreas Dolk
3
Releyendo mi propia pregunta un año después, se me ocurre que podría haber eliminado los constructores (incluidos los de la clase base) como sugirió Matt b, y luego usar un método de fábrica estático para construir instancias.
Joel

Respuestas:

146

Obtiene este error porque una clase que no tiene constructor tiene un constructor predeterminado , que no tiene argumentos y es equivalente al siguiente código:

public ACSubClass() {
    super();
}

Sin embargo, dado que su BaseClass declara un constructor (y, por lo tanto, no tiene el constructor predeterminado sin argumentos que el compilador proporcionaría de otra manera), esto es ilegal: una clase que extiende BaseClass no puede llamar super();porque no hay un constructor sin argumentos en BaseClass.

Esto probablemente sea un poco contrario a la intuición porque podría pensar que una subclase tiene automáticamente cualquier constructor que tenga la clase base.

La forma más sencilla de evitar esto es que la clase base no declare un constructor (y por lo tanto tenga el constructor no-arg predeterminado) o tenga un constructor declarado no-arg (ya sea por sí mismo o junto con cualquier otro constructor). Pero a menudo este enfoque no se puede aplicar, porque necesita los argumentos que se pasen al constructor para construir una instancia legítima de la clase.

mate b
fuente
17
"Esto probablemente sea un poco contrario a la intuición porque podría pensar que una subclase tiene automáticamente cualquier constructor que tenga la clase base". +1
Mr_and_Mrs_D
2
Por el bien de la posteridad, sugeriré mi solución para futuros lectores: cree un constructor sin argumentos en BaseClasspero hágalo simplemente lanzar un UnsupportedOperationExceptiono algo. No es la mejor solución (sugiere falsamente que la clase puede admitir un constructor sin argumentos), pero es la mejor que se me ocurre.
JMTyler
49

Para aquellos que buscan en Google este error y llegan aquí: puede haber otra razón para recibirlo. Eclipse da este error cuando tiene la configuración del proyecto: la configuración del sistema no coincide.

Por ejemplo, si importa el proyecto Java 1.7 a Eclipse y no tiene 1.7 configurado correctamente, obtendrá este error. A continuación, puede ir a cualquiera Project - Preference - Java - Compilery switch to 1.6 or earlier; o vaya a Window - Preferences - Java - Installed JREsy agregue / arregle su instalación de JRE 1.7.

MF.OX
fuente
2
Recibí este error sin motivo aparente en Eclipse. Luego limpié el espacio de trabajo (menú Proyecto -> Limpiar ...) y desapareció.
erickrf
7

Es posible, pero no de la forma en que lo tiene.

¡Tienes que agregar un constructor sin argumentos a la clase base y eso es todo!

public abstract class A {
    private String name;
    public A(){
        this.name = getName();
    }
    public abstract String getName();


    public String toString(){
        return "simple class name: " + this.getClass().getSimpleName() + " name:\"" + this.name + "\"";
    }
}
class B extends A {
    public String getName(){
        return "my name is B";
    }
    public static void main( String [] args ) {
        System.out.println( new C() );
    }
}
class C extends A {
    public String getName() {
        return "Zee";
    }
}

Cuando no agrega un constructor (cualquiera) a una clase, el compilador agrega el constructor predeterminado sin arg para usted.

Cuando el defualt no arg llama a super (); y como no lo tiene en la superclase, aparece ese mensaje de error.

Esa es la pregunta en sí misma.

Ahora, ampliando la respuesta:

¿Es consciente de que crear una subclase (comportamiento) para especificar un valor (datos) diferente no tiene sentido? Espero que lo hagas.

Si lo único que cambia es el "nombre", ¡una sola clase parametrizada es suficiente!

Entonces no necesitas esto:

MyClass a = new A("A");
MyClass b = new B("B");
MyClass c = new C("C");
MyClass d = new D("D");

o

MyClass a = new A(); // internally setting "A" "B", "C" etc.
MyClass b = new B();
MyClass c = new C();
MyClass d = new D();

Cuando puedes escribir esto:

MyClass a = new MyClass("A");
MyClass b = new MyClass("B");
MyClass c = new MyClass("C");
MyClass d = new MyClass("D");

Si tuviera que cambiar la firma del método del constructor BaseClass, tendría que cambiar todas las subclases.

Bueno, es por eso que la herencia es el artefacto que crea un acoplamiento ALTO, lo cual no es deseable en los sistemas OO. Debería evitarse y quizás reemplazarse con composición.

Piense si realmente los necesita como subclase. Es por eso que ve muy a menudo que se usan interfaces en:

 public interface NameAware {
     public String getName();
 }



 class A implements NameAware ...
 class B implements NameAware ...
 class C ... etc. 

Aquí B y C podrían haber heredado de A lo que habría creado un acoplamiento muy ALTO entre ellos, al usar interfaces el acoplamiento se reduce, si A decide que ya no será "NameAware", las otras clases no se romperán.

Por supuesto, si desea reutilizar el comportamiento, esto no funcionará.

OscarRyz
fuente
2
Sí, excepto que ya no puede asegurarse de que sus instancias se inicialicen correctamente (por ejemplo, tener nombres en este caso particular)
ChssPly76
@ ChssPly76: Sí, pero probablemente se deba a que la herencia se está utilizando de manera deficiente. Amplié mi respuesta para cubrirlo.
OscarRyz
4

También puede obtener este error cuando JRE no está configurado. Si es así, intente agregar la biblioteca del sistema JRE a su proyecto.

Bajo Eclipse IDE:

  1. abra el menú Proyecto -> Propiedades , o haga clic con el botón derecho en su proyecto en el Explorador de paquetes y elija Propiedades (Alt + Enter en Windows, Comando + I en Mac)
  2. haga clic en Java Build Path y luego en la pestaña Bibliotecas
  3. elija Modulepath o Classpath y presione el botón Agregar biblioteca ...
  4. seleccione Biblioteca del sistema JRE y luego haga clic en Siguiente
  5. mantenga seleccionado el JRE predeterminado de Workspace (también puede elegir otra opción) y haga clic en Finalizar
  6. finalmente presione Aplicar y Cerrar .
yogesh kumar
fuente
2

Otra forma es llamar a super () con el argumento requerido como primera declaración en el constructor de la clase derivada.

public class Sup {
    public Sup(String s) { ...}
}

public class Sub extends Sup {
    public Sub() { super("hello"); .. }
}
usuario2407102
fuente
0

Eclipse dará este error si no tiene una llamada al constructor de superclase como primera declaración en el constructor de subclase.

Sagar
fuente
0

Lo siento por necropostar pero enfrenté este problema hoy Para todos los que también enfrentan este problema, una de las posibles razones, no se llama supera la primera línea del método. La segunda, la tercera y otras líneas disparan este error. La llamada de super debe ser la primera llamada en su método. En este caso todo va bien.

Serj. De
fuente
0

He resuelto el problema anterior de la siguiente manera:

  1. Haga clic en Proyecto.
  2. haga clic en propiedades> Ruta de compilación Java> Biblioteca> Biblioteca del sistema JRE> Editar
  3. Seleccione el sistema predeterminado JRE y finalice
  4. Aplicar y cerrar.
Uttam Pawar
fuente
-1

Puede resolver este error agregando un constructor sin argumentos a la clase base (como se muestra a continuación).

Salud.

 abstract public class BaseClass {
        // ADD AN ARGUMENTLESS CONSTRUCTOR TO THE BASE CLASS
        public BaseClass(){
        }

        String someString;
        public BaseClass(String someString) {
            this.someString = someString;
        }
        abstract public String getName();
    }

public class ACSubClass extends BaseClass {
    public ASubClass(String someString) {
        super(someString);
    }
    public String getName() {
        return "name value for ASubClass";
    }
}
BrainO2
fuente
Eso facilita la construcción de objetos no válidos (los que no tienen someString) un conjunto y, por lo tanto, frustra totalmente el propósito de como constructor.
Robert
-1

Tuve este error y lo solucioné eliminando una excepción lanzada al lado del método a un bloque try / catch

Por ejemplo: DE:

public static HashMap<String, String> getMap() throws SQLException
{

}

A:

public static Hashmap<String,String> getMap()
{
  try{

  }catch(SQLException)
  { 
  }
}
Thomas Johnson
fuente
Esta respuesta no tiene nada que ver con los errores del compilador de un constructor faltante.
Robert