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

2024-01-16

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

public abstract class BasicPage extends WebPage {

    public BasicPage() {
        add(new Label("title", getTitle()));
    }

    protected abstract String getTitle();

}

NetBeans 警告我消息“构造函数中可重写方法调用”,但它应该有什么问题呢?我能想到的唯一选择是将抽象方法的结果传递给子类中的超级构造函数。但如果有很多参数,这可能很难阅读。


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

简而言之,这是错误的,因为它不必要地开启了以下可能性:MANY错误。当。。。的时候@Override被调用时,对象的状态可能不一致和/或不完整。

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

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

下面举一个例子来说明:

public class ConstructorCallsOverride {
    public static void main(String[] args) {

        abstract class Base {
            Base() {
                overrideMe();
            }
            abstract void overrideMe(); 
        }

        class Child extends Base {

            final int x;

            Child(int x) {
                this.x = x;
            }

            @Override
            void overrideMe() {
                System.out.println(x);
            }
        }
        new Child(42); // prints "0"
    }
}

在这里,当Base构造函数调用overrideMe, Child尚未完成初始化final int x,并且该方法得到错误的值。这几乎肯定会导致错误和错误。

相关问题

  • 从父类构造函数调用重写的方法 https://stackoverflow.com/questions/2898422/calling-an-overridden-method-from-a-parent-class-constructor
  • 当基类构造函数调用Java中重写方法时派生类对象的状态 https://stackoverflow.com/questions/3330390/state-of-derived-class-object-when-base-class-constructor-calls-overridden-method
  • 在抽象类的构造函数中使用抽象 init() 函数 https://stackoverflow.com/questions/3342784/using-abstract-init-function-in-abstract-classs-constructor

See also

  • FindBugs - 从超类的构造函数调用的字段方法的未初始化读取 http://findbugs.sourceforge.net/bugDescriptions.html#UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR

关于具有多个参数的对象构造

具有许多参数的构造函数可能会导致可读性较差,但存在更好的替代方案。

这是引用自《Effective Java》第二版,第 2 条:面对许多构造函数参数时考虑构建器模式:

传统上,程序员使用伸缩构造函数模式,其中您提供一个仅具有必需参数的构造函数,另一个具有单个可选参数,第三个具有两个可选参数,依此类推...

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

public class Telescope {
    final String name;
    final int levels;
    final boolean isAdjustable;

    public Telescope(String name) {
        this(name, 5);
    }
    public Telescope(String name, int levels) {
        this(name, levels, false);
    }
    public Telescope(String name, int levels, boolean isAdjustable) {       
        this.name = name;
        this.levels = levels;
        this.isAdjustable = isAdjustable;
    }
}

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

new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);

但是,目前您不能仅设置name and isAdjustable,并离开levels默认情况下。你可以提供更多的构造函数重载,但显然这个数字会随着参数数量的增长而爆炸,甚至可能有多个boolean and int争论,这真的会让事情变得一团糟。

正如您所看到的,这不是一个写起来令人愉快的模式,使用起来更不愉快(“true”在这里意味着什么?13 是什么?)。

Bloch 建议使用构建器模式,它允许您编写如下所示的内容:

Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();

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

See also

  • 维基百科/构建器模式 http://en.wikipedia.org/wiki/Builder_pattern
  • 《Effective Java》第二版,第 2 条:面对许多构造函数参数时考虑构建器模式 (网上摘录 http://www.codeproject.com/KB/books/EffectiveJava.aspx)

相关问题

  • 你什么时候会使用建造者模式? https://stackoverflow.com/questions/328496/when-would-you-use-the-builder-pattern
  • 这是众所周知的设计模式吗?它叫什么名字? https://stackoverflow.com/questions/2637268/is-this-a-well-known-design-pattern-what-is-its-name/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 检索和设置 IntelliJ IDEA 插件开发的拆分窗口设置

    我正在编写一个 IntelliJ IDEA 插件 用于保存打开选项卡的会话 称为选项卡会话 https github com alp82 idea tabsession 这个问题是后续问题IntelliJ IDEA 插件开发 保存选项卡组
  • 抽象类、构造函数和 Co

    嗯 我正在尝试重用 C 代码的一部分 它是一个带有UDP服务器的抽象类 可以在这里看到 http clutch inc com blog p 4 http clutch inc com blog p 4 我创建了一个像这样的派生类 publ
  • 如何在不改变的情况下将字符串转换为字节?

    我需要一个解决方案将字符串转换为字节数组而不需要像这样进行更改 Input String s Test Output String s Test byte b Test 当我使用 s getBytes 那么回复是 B 428b76b8 但我
  • 如何限制用户键入时 JTextPane 中的字符数 (Java)

    我需要不允许在输入 X 后输入任何字符 我需要在输入 X 个字符后发出蜂鸣声 我知道如何在用户按 Enter 键后执行此操作 但我需要在用户按 Enter 键之前执行此操作 我从 Oracle 站点找到的方法是将 DocumentSizeF
  • PHP 继承以及静态方法和属性

    PHP 中的静态属性和方法不能被继承吗 一些例子会有所帮助 不 那不是真的 静态方法和属性 http www php net manual en language oop5 static php将会得到遗传 http www php net
  • 在 Perl 中,如何将一个函数作为另一个函数的参数传递?

    我编写了以下 Perl 类 package Menu use strict my MENU ITEMS my HEADER Pick one of the options below n my INPUT REQUEST Type your
  • java“类文件包含错误的类”错误

    我正在尝试制作一个控制台应用程序来测试我的网络服务 我成功部署了一个网络服务http localhost 8080 WS myWS http localhost 8080 WS myWS我用 wsimport 制作了代理类 wsimport
  • 为什么这不会导致 NullPointerException?

    public class Null public static void greet System out println Hello world public static void main String args Null null
  • java中main的返回类型

    我想知道为什么java中main方法只有void返回类型 public static void main String args 为什么main方法除了void之外没有其他返回类型 Thanks 简短的回答是 因为这就是语言规范 http
  • Java中通过FTP创建文件夹层次结构

    Java 是否有现成的功能可以在远程 FTP 服务器上创建文件夹层次结构 Apache Commons 确实提供了 FTP 客户端 但我找不到创建目录层次结构的方法 它确实允许创建单个目录 makeDirectory 但创建整个路径似乎并不
  • 将 @RequestLine 与 Feign 一起使用

    我有一个工作 Feign 接口定义为 FeignClient content link service public interface ContentLinkServiceClient RequestMapping method Requ
  • 当另一个线程发生事情时从主线程获取数据?

    目前我有一个线程正在运行一个侦听连接的套接字 当它收到连接时 它需要上传在主线程中收集的数据 即从主线程获取数据 但是 我传递了对象的实例 但它从未使用等待连接时收集的数据进行更新 有没有正确的方法来做到这一点 我用谷歌搜索了一下 似乎找不
  • 这个finally子句包含close()调用的原因是什么

    我正在学习在线java课程 使用 Java 编程简介 http math hws edu javanotes index html 在 I O 章节中 引入了以下代码 顺便说一下 在本程序的末尾 您将发现我们第一个有用的 try 语句中的
  • 捕获 XSS(跨站脚本)攻击的最佳正则表达式(Java 中)?

    杰夫实际上在净化 HTML http refactormycode com codes 333 sanitize html 但他的示例是用 C 编写的 而我实际上对 Java 版本更感兴趣 有人有更好的 Java 版本吗 他的示例是否足以直
  • 使用 Mockitos 传递参数化输入

    我正在使用 Mockito 进行单元测试 我想知道是否可以使用 Junit 测试中的方式发送参数化输入参数 e g InjectMocks MockClass mockClass new MockClass Test public void
  • 在Java程序中计算zip文件的md5哈希值

    我有一个 zip 文件 在我的 Java 代码中我想计算 zip 文件的 md5 哈希值 有没有我可以用于此目的的 java 库 一些例子将非常感激 谢谢 几周前我通过这篇文章做到了这一点 http www javalobby org ja
  • Java 8 Stream - 为什么过滤器方法不执行? [复制]

    这个问题在这里已经有答案了 我正在学习使用java流进行过滤 但是过滤后的流没有打印任何内容 我认为过滤器方法没有被执行 我的过滤代码如下 Stream of d2 a2 b1 b3 c filter s gt s startsWith b
  • Web服务连接超时和请求超时之间的区别

    WebClientTestService service new WebClientTestService int connectionTimeOutInMs 5000 Map
  • JBoss 5 截断 base64 cookie 字符串的尾部 =

    从 JBoss 4 升级到 JBoss 5 后 我注意到最烦人的回归 它截断 base64 cookie 值的尾部等号 我花了很长时间才明白问题不是我的代码而是 JBoss 的 我用 google 搜索了一下 发现这是一个已知的问题issu
  • 用于从链表中删除元素的大 O 表示法[重复]

    这个问题在这里已经有答案了 我正在阅读有关链接列表的内容 我发现 从链表中删除所需的元素需要 O n 运行时间 其中 n 是元素的数量 列表中的元素 http www cs mcgill ca dprecup courses IntroCS

随机推荐