我在Java中有以下示例类:
public class A { }
public class Super {
protected Super() { }
public Super(A a) { }
}
public class Sub extends Super { }
public class Consumer {
public Consumer() {
Sub sub = new Sub(new A()); //compiler error
}
}
编译器错误表明参数不能应用于Sub中的默认构造函数,这是完全可以理解的。
我很好奇的是这个决定背后的理由。 Java在Sub
中生成默认的空构造函数;为什么不能在这种情况下在幕后调用呢?这主要是一个理智的手持,还是有技术原因?
编辑
我知道 这是一种语言限制。我很好奇为什么这是一种语言限制。
编辑2
似乎通常情况下,我太过接近我实际工作的代码,看看大局。我在下面的答案中发布了一个反例,说明了为什么这是BadThing®。
答案 0 :(得分:2)
public class Sub extends Super { }
没有构造函数Sub(A a),它只有默认构造函数Sub()。
构造函数不是继承的。
答案 1 :(得分:2)
基类需要调用超级构造函数,以确保正确实例化对象。例如,考虑:
class Super {
final String field1;
public Super(String field1) {
this.field1 = field1;
}
...
}
class Base extends Super {
final String field2;
public Base(String field2) {
this.field2 = field2;
}
...
}
Base
的构造函数是否会覆盖Super
构造函数?如果是这样,则不再保证field1被初始化,使得继承的方法出乎意料地行为。
当您向子类添加非默认构造函数时,继承的构造函数将停止工作。我认为这是一个令人困惑且很少有用的功能,它被添加到语言中,虽然从技术上来说,我没有理由认为它不可能。
答案 2 :(得分:2)
我认为这是一个既可读性也不假设意图的问题。你说
Java生成默认的空构造函数;为什么不能在这种情况下在幕后调用呢?
然而对我而言,Java隐含地在幕后调用Super(A)
构造函数“比调用Super()
构造函数更加有意义,而忽略A
。
你有它。在这种情况下,我们已经有两个完全不同的假设(或可以)。
Java语言的核心原则之一是透明度。程序员应该尽可能地通过查看代码将会发生什么,有时以牺牲便利性或语法级别的 magic 为代价。
与此并行的原则并不是假设意图:在程序员的意图看似含糊不清的情况下,Java语言有时会支持编译错误,而不是通过某些(任意或其他)选择算法自动选择默认值。
答案 3 :(得分:0)
您已经覆盖了默认的公共构造函数,因此无法调用任何内容。
所以类Sub相当于
public class Sub extends Super
{
protected Sub(){}
public Sub(A a) { }
}
这是因为它的
答案 4 :(得分:0)
我将此作为此行为的技术原因;我同意其他几个答案,这可能在语义上令人困惑。
考虑以下示例:
public class A { }
public abstract class Super {
protected Super() {
// perform time consuming, destructive, or
// otherwise one-time operations
}
public Super(A a) {
this();
// perform A-related construction operations
}
}
public class Sub extends Super { }
public class Consumer {
public Consumer() {
Sub sub = new Sub(new A());
}
}
构造Sub
时,在这种情况下会调用Sub
上的默认构造函数,它将链接到Super
上的默认构造函数(因为这是语言定义的魔力) )。然后,对Super(A)
的调用将调用在构造时设计为运行一次的逻辑。这显然不是开发人员想要的。
即使没有this()
构造函数中的Super(A)
调用,开发人员的意图也无法确定;由于某种原因,构造函数可能是互斥的。