2009-07-29 8 views
84

Tengo un poco de código Java simple que tiene una apariencia similar a esto en su estructura:de error de Java: super constructor implícito no está definida para constructor por defecto

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"; 
    } 
} 

voy a tener un buen número de subclases de BaseClass, la implementación de cada uno de la getName() método de su propia manera (template method pattern).

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 tuviera que cambiar la firma del método del constructor BaseClass, tendría que cambiar todas las subclases.

Cuando quito el constructor de las subclases, me sale este error en tiempo de compilación:

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

es lo que estoy tratando de hacer posible?

+1

¡Por favor, deje el constructor 'redundante'! Mantiene la legibilidad de su código y todos los IDEs modernos pueden crearlo automáticamente, por lo que solo tiene que marcar un atajo. –

+3

Releyendo mi propia pregunta un año después y se me ocurre que podría haber eliminado los constructores (incluidos en la clase base) como se sugirió matt b, y luego usar un método de fábrica estático para crear instancias. – Joel

Respuesta

138

obtiene este error debido a una clase que no tiene constructor tiene un valor predeterminado constructor , que es argumento de menos y es equivalente al siguiente código:

public ACSubClass() { 
    super(); 
} 

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

Esto es probablemente un poco contra-intuitivo 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 así tenga el constructor predeterminado no-arg) o tenga un constructor no-arg declarado (solo o junto a cualquier otro constructor). Pero a menudo este enfoque no se puede aplicar, porque necesita que se pasen los argumentos al constructor para construir una instancia legítima de la clase.

+16

"Esto es probablemente un poco contra-intuitivo porque podría pensar que una subclase tiene automáticamente cualquier constructor que tenga la clase base". +1 –

+1

Por el bien de la posteridad, sugeriré mi solución para lectores futuros: crear un constructor sin argumentos en 'BaseClass' pero simplemente lanzar una' UnsupportedOperationException' o algo así. No es la mejor solución (sugiere falsamente que la clase puede soportar un constructor sin argumentos), pero es lo mejor que se me ocurre. – JMTyler

7

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

Tienes que agregar un constructor no-args 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 se agrega un constructor (ninguna) a una clase el compilador añadir el valor por defecto sin contructor arg para usted.

Cuando el defualt no arg llama a super(); y como no lo tienes en la súper clase, recibes ese mensaje de error.

Eso es todo sobre la pregunta.

Ahora, la ampliación de la respuesta:

¿Sabe usted que la creación de una subclase (comportamiento) para especificar un valor diferente diferente (datos) que no tiene sentido ?? !!! Espero que lo hagas.

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

Así que no es necesario 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 se puede escribir lo siguiente:

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

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

Bien por eso la herencia es el artefacto que crea un acoplamiento ALTO, que es unde sirable en sistemas OO. Debe evitarse y tal vez reemplazarse con la composición.

Piensa si realmente las necesitas como subclase. Es por eso que se ve muy a menudo interfaces utilizadas insted:

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, que habría creado un acoplamiento muy alta entre ellos, mediante el uso de las interfaces se reduce el acoplamiento, si A decide que lo hará ya no será "NameAware", las otras clases no se romperán.

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

+2

Sí, excepto que ya no puede asegurarse de que sus instancias se hayan inicializado correctamente (por ejemplo, tienen nombres en este caso particular) – ChssPly76

+0

@ ChssPly76: Sí, pero eso es probablemente debido a que la herencia se está utilizando de forma incorrecta. Expandí mi respuesta para cubrirlo. – OscarRyz

0

su BaseClass necesita un string para que entregue uno.
Prueba esto:

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

public class ACSubClass extends BaseClass { 
    public ASubClass() { 
     super("someString"); // or a meaningfull value, same as getName()? 
    } 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 

o

abstract public class BaseClass { 
    String someString; 
    protected BaseClass() { // for subclasses 
     this.someString = null; // or a meaningfull value 
    } 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

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

Para los que Google de este error y llegar aquí: podría haber otra razón para que lo recibe. Eclipse proporciona 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. Entonces puede ir a Project - Preference - Java - Compiler y switch to 1.6 or earlier; o vaya al Window - Preferences - Java - Installed JREs y agregue/corrija su instalación de JRE 1.7.

+1

Acabo de recibir este error sin razón aparente en Eclipse. Luego limpié el espacio de trabajo (menú Proyecto -> Limpiar ...) y desapareció. – erickrf

-1

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

Saludos.

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"; 
    } 
} 
+0

Eso hace que sea fácil construir objetos inválidos (los que no tienen 'someString') establecidos y, por lo tanto, anula por completo el propósito de como constructor. – Robert

0

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

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

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

Eclipse dará este error si no tiene una llamada a super constructor de clase como una primera declaración en constructor de la subclase.

-1

Tenía este error y se fija mediante la eliminación de una excepción lanzada desde 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) 
    { 
    } 
} 
+0

Esta respuesta no tiene nada que ver con los errores del compilador de un constructor faltante. – Robert

1

este error se debe a que JRE no se configuró, por favor, siga estos pasos:


1. haga clic derecho k proyecto -> Propiedades -> Java Build Path -> Haga clic en la pestaña Bibliotecas
2. haga clic en Agregar biblioteca
3. Seleccione Biblioteca del sistema JRE -> Haga clic en Siguiente
4. Elija área de trabajo jre predeterminada o jre instalada alternativa
5. haga clic en finalizar

+0

Gosh, el OP ni siquiera dijo qué IDE (si hay alguno) que está usando ... – Robert

0

Lo siento por necroposting, pero se enfrentó a este problema hoy. Para todos los que también enfrentan este problema, uno de los posibles motivos, no llames al super en la primera línea de método. La segunda, la tercera y otras líneas activan este error. Call of super debería ser la primera llamada en tu método. En este caso, todo está bien.

Cuestiones relacionadas