构造函数中的可重写方法调用有什么问题?

我有一个Wicket page类,它根据抽象方法的结果设置页面标题

公共抽象类BasicPage扩展网页{
公共基础设施(){
添加(新标签(“标题”,getTitle());
}
受保护的抽象字符串getTitle();
}

NetBeans用消息“构造函数中可重写的方法调用”警告我,但它有什么错呢?我能想象的唯一替代方法是将其他抽象方法的结果传递给子类中的超级构造函数。但这可能很难用许多参数来理解

从构造函数调用可重写方法

简单地说,这是错误的,因为它不必要地为许多bug提供了可能性。调用@Override时,对象的状态可能不一致和/或不完整

引用自《有效Java第二版》第17项:继承的设计和文档,否则禁止它

类还必须遵守一些限制才能允许继承构造函数不能直接或间接调用可重写方法。如果违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前调用。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期的方式运行

下面是一个例子来说明:

公共类构造函数调用{
公共静态void main(字符串[]args){
抽象类基{
Base(){
覆盖位();
}
抽象无效覆盖eme();
}
类子扩展基{
最终整数x;
儿童(int x){
这个.x=x;
}
@凌驾
无效覆盖项(){
系统输出println(x);
}
}
新子级(42);//打印“0”
}
}

这里,当Base构造函数调用overrideMe时,子项尚未完成初始化最终整数x,并且该方法获取了错误的值。这几乎肯定会导致bug和错误

相关问题

另见


关于多参数对象构造

具有许多参数的构造函数可能导致可读性差,并且存在更好的替代方法

这是一个引用EME>有效java第二版,项目2:考虑当遇到许多构造函数参数:

时的构造器模式

传统上,程序员使用伸缩构造函数模式,在这种模式中,您只提供一个构造函数和所需的参数,另一个构造函数和一个可选参数,第三个构造函数和两个可选参数,依此类推

伸缩构造函数模式基本上是这样的:

公共类望远镜{
最后的字符串名;
最终智力水平;
最终布尔值是可调整的;
公共望远镜(字符串名称){
这个(名字,5);
}
公共望远镜(字符串名称,整数级别){
这(名称、级别、错误);
}
公共望远镜(字符串名称,整数级别,布尔值可调整){
this.name=名称;
这个。级别=级别;
this.isAdjustable=isAdjustable;
}
}

现在,您可以执行以下任一操作:

新望远镜(“X/1999”);
新望远镜(“X/1999”,13);
新望远镜(“X/1999”,13,真);

但是,您当前无法仅设置名称可调整,并将级别保留为默认值。您可以提供更多的构造函数重载,但很明显,随着参数数量的增加,这个数量会急剧增加,甚至可能有多个booleanint参数,这会让事情变得一团糟

正如你所看到的,这不是一个令人愉快的模式,使用起来更不愉快(这里“真”是什么意思?13是什么?)

Bloch建议使用builder模式,这将允许您编写如下内容:

望远镜电视=新望远镜.Builder(“X/1999”).setAdjustable(true.build();

请注意,现在这些参数已命名,您可以按任意顺序设置它们,并且可以跳过希望保留为默认值的参数。这当然比伸缩构造函数好得多,特别是当有大量属于许多相同类型的参数时

另见

相关问题

发表评论