问题
我有一些简单的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()方法(template method pattern)。
这很好用,但我不喜欢在子类中使用冗余构造函数。打字更多,难以维护。如果我要更改BaseClassconstructor的方法签名,我将不得不更改所有子类。
当我从子类中删除构造函数时,我得到了这个编译时错误:
Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor
我正在尝试做什么?
#1 热门回答(140 赞)
你收到此错误,因为没有构造函数的类具有a默认值constructor,它是无参数且等效于以下代码:
public ACSubClass() {
super();
}
但是,由于你的BaseClass声明了一个构造函数(因此没有编译器可能提供的默认的no-arg构造函数)这是非法的 - 扩展BaseClass的类不能调用super();,因为没有无参数构造函数BaseClass的。
这可能有点违反直觉,因为你可能认为子类自动拥有基类具有的任何构造函数。
最简单的方法是让基类不声明构造函数(因此具有默认的无参数构造函数)或具有声明的无参数构造函数(无论是单独使用还是与任何其他构造函数一起)。但是通常不能应用这种方法 - 因为你需要将任何参数传递给构造函数来构造类的合法实例。
#2 热门回答(42 赞)
对于那些谷歌这个错误并到达这里的人:可能有另一个原因接收它。当你进行项目设置时,Eclipse会出现此错误 - 系统配置不匹配。
例如,如果你将Java 1.7项目导入Eclipse并且没有正确设置1.7,那么你将收到此错误。然后你可以去Project - Preference - Java - Compiler和switch to 1.6 or earlier;或者转到Window - Preferences - Java - Installed JREs并添加/修复你的JRE 1.7安装。
#3 热门回答(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";
}
}
如果不向类添加构造函数(any),编译器会为你添加缺省的无参数构造函数。
当defualt没有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",其他类将不会破坏。
当然,如果你想重用行为,这将无法工作。