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

Joe*_*oel 87 java inheritance dry boilerplate

我有一些简单的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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

这很好用,但我不喜欢在子类中使用冗余构造函数.打字更多,难以维护.如果我要更改BaseClass构造函数的方法签名,我将不得不更改所有子类.

当我从子类中删除构造函数时,我得到了这个编译时错误:

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

我正在尝试做什么?

mat*_*t b 144

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

public ACSubClass() {
    super();
}
Run Code Online (Sandbox Code Playgroud)

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

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

最简单的方法是让基类不声明构造函数(因此具有默认的,无参数构造函数)或具有声明的无参数构造函数(无论是单独使用还是与任何其他构造函数一起).但是通常不能应用这种方法 - 因为你需要将任何参数传递给构造函数来构造类的合法实例.

  • "这可能有点违反直觉,因为您可能认为子类自动拥有基类具有的任何构造函数." +1 (17认同)
  • 为了后代,我将为未来的读者提出我的解决方案:在`BaseClass`中创建一个无参数的构造函数,但只需抛出一个`UnsupportedOperationException`或其他东西.这不是最好的解决方案(它错误地表明该类可以支持无参数构造函数),但这是我能想到的最好的解决方案. (2认同)

MF.*_*.OX 46

对于那些谷歌因此错误而到达此处的人:可能还有其他原因可以接收它.当您进行项目设置时,Eclipse会出现此错误 - 系统配置不匹配.

例如,如果您将Java 1.7项目导入Eclipse并且没有正确设置1.7,那么您将收到此错误.然后你可以去Project - Preference - Java - Compilerswitch to 1.6 or earlier; 或者去Window - Preferences - Java - Installed JREs添加/修复您的JRE 1.7安装.

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

Osc*_*Ryz 7

这是有可能的,但不是你的方式.

你必须在基类中添加一个no-args构造函数,就是这样!

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";
    }
}
Run Code Online (Sandbox Code Playgroud)

如果不向类添加构造函数(any),编译器会为您添加默认的no arg构造函数.

当defualt没有arg调用super(); 并且由于您没有在超类中使用它,因此您会收到该错误消息.

这是关于它自己的问题.

现在,扩大答案:

你是否意识到创建一个子类(行为)以指定不同的值(数据)是没有意义的?? !!! 我希望你会.

如果唯一改变的是"名称",那么参数化的单个类就足够了!

所以你不需要这个:

MyClass a = new A("A");
MyClass b = new B("B");
MyClass c = new C("C");
MyClass d = new D("D");
Run Code Online (Sandbox Code Playgroud)

要么

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

当你写这个:

MyClass a = new MyClass("A");
MyClass b = new MyClass("B");
MyClass c = new MyClass("C");
MyClass d = new MyClass("D");
Run Code Online (Sandbox Code Playgroud)

如果我要更改BaseClass构造函数的方法签名,我将不得不更改所有子类.

那么这就是继承是产生HIGH耦合的工件的原因,这在OO系统中是不可取的.应该避免它,也许应该用组合物代替.

想想你是否真的需要它们作为子类.这就是为什么你经常看到使用insted的接口:

 public interface NameAware {
     public String getName();
 }



 class A implements NameAware ...
 class B implements NameAware ...
 class C ... etc. 
Run Code Online (Sandbox Code Playgroud)

这里B和C可以继承自A,它可以在它们之间创建一个非常高的耦合,通过使用接口减少耦合,如果A决定它将不再是"NameAware",其他类将不会破坏.

当然,如果您想重用行为,这将无效.

  • 是的,除非您无法再确保您的实例已正确初始化(例如,在此特定情况下具有名称) (2认同)