Java错误:未为默认构造函数定义隐式超级构造函数


88

我有一些简单的Java代码,其结构与此类似:

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

我将有很多子类BaseClass,每个子类以getName()自己的方式(模板方法模式)实现方法。

这很好用,但是我不喜欢子类中有多余的构造函数。输入更多,难以维护。如果要更改BaseClass构造函数的方法签名,则必须更改所有子类。

当我从子类中删除构造函数时,出现此编译时错误:

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

我想做的事可能吗?


1
请离开“冗余”构造函数!它保持了代码的可读性,并且所有现代IDE都可以自动创建代码,因此您只需键入快捷方式即可。
Andreas Dolk,2009年

3
一年后重新阅读了我自己的问题,我想到我可以像建议的matt b那样删除构造函数(包括基类中的构造函数),然后使用静态工厂方法来构建实例。
乔尔2010年

Answers:


145

您会收到此错误,因为没有构造函数的类具有默认构造函数,该构造函数没有参数,并且等效于以下代码:

public ACSubClass() {
    super();
}

但是,由于您的BaseClass声明了一个构造函数(因此没有默认值,否则将由编译器提供无参数的构造函数),这是非法的-扩展BaseClass的类无法调用 super();因为没有无参数的构造函数在BaseClass中。

这可能有点违反直觉,因为您可能认为子类会自动具有基类所具有的任何构造函数。

解决此问题的最简单方法是,基类不声明构造函数(因此具有默认的无参数构造函数)或具有声明的无参数构造函数(单独或与其他任何构造函数一起使用)。但是这种方法通常无法应用-因为您需要将任何参数传递到构造函数中,以构造类的合法实例。


17
“这可能有点违反直觉,因为您可能认为子类自动具有基类所具有的任何构造函数。” +1
Mr_and_Mrs_D 2013年

2
为了后代的缘故,我将为以后的读者提供我的解决方案:在其中创建一个no-arg构造函数,BaseClass但使其简单地引发一个UnsupportedOperationException或多个东西。这不是最好的解决方案(它错误地暗示该类可以支持无参数构造函数),但这是我能想到的最好的解决方案。
JMTyler

49

对于那些因Google错误而到达此地址的人:可能还有其他原因要接收它。当您进行项目设置时,Eclipse将给出此错误-系统配置不匹配。

例如,如果将Java 1.7项目导入到Eclipse中,但没有正确设置1.7,则会出现此错误。然后,您可以转到Project - Preference - Java - Compilerswitch to 1.6 or earlier; 或转到Window - Preferences - Java - Installed JREs并添加/修复您的JRE 1.7安装。


2
只是在Eclipse中没有明显原因而收到此错误。然后我清理了工作区(菜单Project-> Clean ...),它消失了。
erickrf 2014年

7

这是可能的,但并非您拥有它的方式。

您必须在基类中添加一个无参数的构造函数,仅此而已!

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

当您不向类添加构造函数(any)时,编译器将为您添加默认的no arg构造函数。

当默认时,没有arg调用super();。而且由于您没有在超类中使用它,因此您会收到该错误消息。

那是关于它自己的问题。

现在,扩大答案:

您是否知道创建子类(行为)以指定不同的不同值(数据)是没有意义的?我希望你会。

如果唯一要更改的是“名称”,则只需参数化一个类就足够了!

因此,您不需要:

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

要么

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

当您可以这样写时:

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

如果要更改BaseClass构造函数的方法签名,则必须更改所有子类。

这就是为什么继承是产生HIGH耦合的人工产物的原因,这在OO系统中是不可取的。应该避免使用它,也许应该用合成代替。

考虑一下是否真的需要它们作为子类。这就是为什么您经常看到使用insted的接口的原因:

 public interface NameAware {
     public String getName();
 }



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

在这里B和C可以从A继承而来,这将在它们之间创建一个非常高的耦合,通过使用接口,耦合将减少,如果A决定不再是“ NameAware”,则其他类将不会中断。

当然,如果您想重用行为,则将不起作用。


2
是的,除了您不能再确保您的实例已正确初始化(例如,在这种情况下使用名称)
ChssPly76 2009年

@ ChssPly76:是的,但这可能是因为继承的使用方式很差。我扩大了回答范围。
OscarRyz

4

当未设置JRE时,您也可能会收到此错误。如果是这样,请尝试将JRE系统库添加到您的项目中。

在Eclipse IDE下:

  1. 打开菜单项目 -> 属性,或在Package Explorer中右键单击您的项目,然后选择Properties(在Windows上为Alt + Enter,在Mac上为Command + I)
  2. 单击Java构建路径,然后单击选项卡
  3. 选择模块路径类路径,然后按添加库...按钮
  4. 选择“ JRE系统库”,然后单击“ 下一步”。
  5. 保持选择Workspace默认JRE(也可以选择其他选项),然后单击“ 完成”。
  6. 最后按Apply and Close

2

另一种方法是使用派生类构造函数中的第一条语句调用带有所需参数的super()。

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

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

0

如果您没有将超类构造函数作为子类构造函数中的第一条语句调用,则Eclipse将给出此错误。


0

很抱歉为您发布死角,但直到今天才面临这个问题。对于也面临这个问题的每个人(他可能的原因之一),您不必super在方法的第一行调用。第二,第三和其他行会触发此错误。调用super应该是您方法中的第一个调用。在这种情况下,一切都很好。


-1

您可以通过在基类中添加无参数构造函数来解决此错误(如下所示)。

干杯。

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

这使得构造无效对象(没有的对象someString)变得容易,因此完全违背了作为构造函数的目的。
罗伯特

-1

我遇到了此错误,并通过从方法旁边将抛出的异常移除到try / catch块来修复了该错误

例如:FROM:

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

}

至:

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

  }catch(SQLException)
  { 
  }
}

对于缺少的构造函数,此答案与编译器错误无关。
罗伯特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.