Why exactly do subclass constructors have to explicitly call super class constructors?
Possible Duplicate:
Why does this() and super() have to be the first statement in a constructor?
为什么子类构造函数必须显式调用超类构造函数?原因是什么?
型
他们没有。
如果不显式调用超级结构,则相当于调用无参数超级结构。
1 2 3 4 5 6 7
| public class Sub
{
public Sub()
{
// Do some stuff
}
} |
相当于:
1 2 3 4 5 6 7 8
| public class Sub
{
public Sub()
{
super();
// Do some stuff
}
} |
号
如果要指定参数,则必须显式调用超结构。这很合理,IMO-你真的想让编译器猜测你想提供哪些参数吗?
- 此外,如果父类没有无参数的构造函数,则需要使用必要的参数显式调用父构造函数。
- @克劳迪奥弗尔南德斯:是的,我希望这是隐含的-如果没有无参数的构造函数,就不能隐式地调用它:)
- 在由JVM创建的超类中,总是有一个无参数的构造函数,只需在命令提示下键入javap classname即可。
- @Abhishekkumar:不,没有。如果没有指定其他构造函数,编译器将提供默认的构造函数。如果使用参数指定一个构造函数,但没有无参数的构造函数,则尝试从子类中隐式调用无参数的构造函数将失败。
- 嗯,为什么不呢?编译器可以通过查看签名来识别要调用的超级结构。如果参数的数量和类型相同,我就不会看到自动识别和避免冗余代码的问题。其他语言也会这样做。
- @佩雷:在这一点上,在超类中引入一个新的构造函数会改变代码的含义,这是一个问题——除非你也说如果没有匹配项,它不应该隐式地调用super()。
- 抱歉@jonsket,但我不明白你在说什么,也不认为这是我提问的答案。假设我的基类中有一个构造函数,它接受一个String参数。如果我扩展我的类,我必须在我的孩子中显式地声明一个采用String的构造函数,如果我不想实现进一步的逻辑,只需对它调用super(myString);。为什么?为什么编译器不能自动推断出这一点?
- @佩雷:不,您不必声明这样的构造函数。可以声明将字符串传递给超类的任何其他类型的构造函数。假设Child(String x) { super(x); }构造函数是自动应用的,您将如何选择退出它?但是在评论中进行进一步的讨论不是一个好主意——可能会有一个新的问题,有一套非常具体的替代语言规则是合适的,但是诚实地说,作为一篇博客文章可能会更好。
- @Jonskeet I不调用在子类中传递字符串的构造函数来"选择退出"。或者重写子类中的构造函数什么也不做,或者抛出一个错误,谁知道呢。对我来说,"继承"意味着直到现在:来自父类的所有方法都是自动继承的,包括重载的构造函数。顺便说一下,这个问题的题目似乎很适合我的疑问,我觉得它根本就没有被回答过…
- @但是,您如何选择退出现有的构造函数?如果一个超类构造函数只接受一个字符串,但您不想要这个构造函数,您怎么说您不想要它?你怎么说你不想要任何额外的构造器,这些构造器以后可能会被添加到超类中?你的"疑问"似乎比这个问题要广泛得多——你的疑问是"为什么构造函数不是继承的",这实际上不是一回事。
- 其他的OOP语言的确有这种行为,这也是我在爪哇所期待的。这叫做继承。如果你的父母以后买了新的财产,你也会继承它。如果希望新的构造函数在派生类中可用,该怎么办?您必须手动将其添加到每个…在我看来,默认情况下继承它们似乎更自然,就像在基中添加任何新方法一样(即使您不希望继承它们,也会继承它们——只是不要使用它们)。无论如何,您必须处理对代码所做的任何修改。我不是个好例子。
- @审判:一些其他的OOP languages,到底有这样的行为,但其他人不T。C #工程相同的方式在Java。如果我是捡了一个英语languages *你说的关于,)正如你是个很惊讶。basically),一个视图技术构建一个非常不同的对象从一个技术用途的一个对象。"只是不要用的东西,你不想要"的方法真的很危险,国际海事组织。这会使它不可能有invariants -如果一切inherited的parameterless constructor从Object例如什么文件,然后从new FileInputStream()会读一读吗?
- @审判:任何方法inherit从你的superclass应该仍然是适用的subclass到……如果不是,这不是很好的使用inheritance。同样的事情不是月亮为你怎么是构建一个对象。我想我们要有对同意到disagree虽然……
- @ jonskeet好,hypothetical情况FileInputStream()也已经出口由compiler不creating的违约parameterless constructor如果基地班已经腹部的一些explicitly declared方法,需要参数。constructors与参数可以通过inherited违约,如果他们(Oracle吗?)希望到和仍然保持电流限制关于parameterless constructor;它是所有关于公约。我不看不见了,怎么会影响到invariants。我也厌倦了看inherited方法,把一个单纯的"unsupported"的例外,虽然我并不同意它看起来如此聪明吗
- @审判:现在你是inventing更多规则上飞,你没有被描述在T。这就是为什么这是不合适的评论线程。又一次,我会到你的家伙写的博客后-或至少在你的一切问题presenting suggesting点。这不是constructive AS的评论线程。
- @ jonskeet好,到我的规则是一样的,我会表示,在我的第一个评论的例外;关于parameterless constructor已经existed和应用是我相信这个discussion fits好的年代subquestions为原来的一个,虽然我同意这是太多的discussion为评论线程。
型
如上所述,如果父类中没有默认的构造函数,则只需调用一个超级构造函数。
这是必需的,因为父类必须由其构造函数中的一个初始化,如果没有默认构造函数,Java编译器就不知道要调用哪个构造函数,或者需要传递哪些参数。
为了更好地理解为什么必须调用父级中的至少一个构造函数,请考虑以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person {
private Person mother;
private Person father;
public Person(Person mother, Person father) {
assert mother != null && father != null:"Parents can't be null!";
this.mother = mother;
this.father = father;
}
public boolean hasAnyLivingParents() {
return mother.isAlive() || father.isAlive();
}
public boolean isAlive() { return true; }
} |
。
如果直接创建Person,则必须指定人员的mother和father,并且hasAnyLivingParents()方法希望指定这些内容。
现在,假设您有一个子类,Employee,并且您不关心员工的父母,因此您希望编写如下内容:
1 2 3 4 5 6 7
| class Employee extends Person {
double salary;
public Employee(double salary) {
this.salary = salary;
}
} |
这不会编译,因为我们不调用Person的构造函数,也没有默认的构造函数。如果这样编译,调用(new Employee(50000d)).hasAnyLivingParents()总是抛出NullPointerException,因为甚至没有初始化mother和father字段。
简而言之,Java要求每个类都由一些构造函数初始化。如果一个类上没有默认的构造函数,则必须调用它的一个其他构造函数来初始化该对象。
型
子类甚至隐式调用父类中存在的非参数化默认构造函数。当我们向构造函数传递参数时,必须显式调用。
- 这是个晴朗的;但为什么?
- @审判比它也stated在javadoc"你没有提供任何constructors为你的类的,但是你必须要小心,当这样做。"compiler automatically提供无argument,违约constructor为舱,没有任何constructors。这constructor违约会知道没有argument constructor之superclass。在这情况,compiler会抱怨,如果superclass没有没有没有argument constructor,所以你必须verify,它确实没有。如果你的类没有显式的superclass腹部,然后它有一个隐含的superclass之对象,回家的时候,有没有argument constructor。"
- 谢谢你为answering,abhishekkumar。我知道这是一个老问题,但我要问的是因为你weren"T"answering原有的一个。我们知道我们已经explicitly打电话的时候,我们不要通过参数 constructor。但他说,我要问的是为什么。我们已经知道做什么。"你也javadoc excerpt CITé腹部小到做的问题。我们必须小心到有非argument constructor在superclass;好的。但问题是一个不同的人。为什么做我要做的super(),单纯的passes同步参数的孩子constructor 韦德和没有什么吗?
- 打电话到(超级)以下是因为"父级必须由一个initialized ITS constructors和,如果有是不是问题的constructor违约,Java compiler腹部没有方式的认识,constructor到呼叫。因此通过internally或explicitly呼叫我们的initailizing舱,由其constructor
- 那么"compiler可以抱怨关于父级不具有constructor。对我,又一次,这不是一个在所有的答案。
- @Pere构造函数调用是链接的;任何时候创建一个对象,都会调用一系列的构造函数方法,从子类到超类,直到类层次结构根的对象。因为超类构造函数总是作为其子类构造函数的第一条语句调用的,所以对象构造函数的主体总是首先运行,其次是其子类的构造函数,并沿着类层次结构向下运行到要实例化的类。这里有一个重要的含义;当调用构造函数时,它可以依靠要初始化的超类的字段。
- 你甚至把我弄糊涂了。真的,我不需要知道这些细节(顺便问一下,你确定是这样做的吗?)我重复一遍:我不想解释它是如何完成的。我只是在问为什么不以一种不同的方式来做,通过查看构造函数的签名来推断应该调用哪个父构造函数,就像其他语言一样,而不必手动执行(如果我可以手动执行,则可以由编译器执行)。这就是全部。
型
1 2 3 4 5 6 7 8 9
| class Parent
{
Parent(int x) {}
}
class Child extends Parent
{
Child(){} // will not compile.
} |
编译器试图调用super()作为Child()构造函数的第一行,但父级没有arg构造函数。因此,在本例中,您必须通过调用super(5)来显式地执行此操作。
- 你可能会有forgotten到extends在给我的孩子。