【问题标题】:Is it possible to chain overridden methods in Java是否可以在Java中链接覆盖的方法
【发布时间】:2013-05-31 05:58:46
【问题描述】:

假设我有一个抽象类:

abstract class DBTable {

    abstract boolean append();

}

而且我还有一个继承自 DBTable 的子类:

// Client objects are rows of a database table
class Client extends DBTable {

    @Override
    boolean append() {

    }
}

最后,假设我有一个 Client 的子类,我用它来表示 Client 对象的非规范化形式(我觉得这没关系。它都在同一个包中,并且 Client.Expand -is a-客户)。

我想做的是覆盖 Client.Expand 中的 append() 方法,并在返回执行仅适用于子类的工作之前将其链接到 Client 中的 append() 方法。像这样的...

    // Expand is a member class of Client
    static class Expand extends Client {

        @Override
        boolean append() {
            super.append();
            :
            :
        }
    }

Java 允许这样做吗?当我尝试覆盖已在父类中覆盖的方法时,我从 IDE 收到错误。看起来我应该能够覆盖一个被覆盖的方法以提供子类所需的额外实现,但也许 Java 不是为这种继承而构建的?

【问题讨论】:

  • 错误说明了什么?
  • Expand 是成员类,还是 Client 的子类?
  • 是的,Expand 是 Client 的静态嵌套类。没关系,不过……静态嵌套类实际上与顶级类相同,只是捆绑为成员类。它应该能够毫无问题地将 Client 扩展为其成员类。
  • 是的,尝试将 Expand 移动到它自己的对象(即不是成员类),并从其声明中删除 static 关键字。如果你这样做,它应该可以工作,许多 Java 框架使用你描述的方法链。
  • @Bhesh,我得到的错误是“这个方法已经在客户端被覆盖”。

标签: java oop inheritance overriding subclass


【解决方案1】:

您的示例存在几个问题:

  1. 当您将类的成员声明为静态时,该成员与该类相关联。它不能与该类的实例一起使用。例如,当您在 Expand 的 append 方法中有一个代码时,例如 - super.append() - “super”指的是一个实例,而不是“class”。因此它与静态定义相矛盾。正如 cmets 中所建议的,您需要从类声明中删除静态。

  2. 一个子类,不应该是一个内部类,这不是一个好的设计,即使它是允许的。因为,如果从语义上考虑,子类不是超类的成员(在这种情况下,父子词具有误导性,超类和子类更好)。超类不应该知道可以扩展它的类,它应该是自包含的。因此,最好将子类移到单独的类中。

  3. 您的设计还有一些其他问题:首先,命名不是对主题的描述。如果 client 代表一行,那么 Row 或 TableRow, ... 可能是一个更好的名称,而下一个类则为 ExpendedRow。

但是,更重要的是,扩展表的行并不是一个好主意。更好的方法可能是让 Row 类和 Table 类组成 Row。像这样的:

// Client objects are rows of a database table
class Row {

    @Override
    boolean append() {

    }
}

class Expanded extends Row{

        @Override
        boolean append() {
            super.append();
            :
            :
        }
    }
class DBTable {

    Row row;

}

【讨论】:

  • 尊敬的,您似乎对静态成员类有点困惑。请记住,对于 JVM,静态成员类与顶级类没有什么不同。对程序员来说,成员类保留了词法、句法关系(例如,Client.Expand),但编译器将静态成员类重命名为 Client$Expand,它变得就像任何其他顶级类一样。因为这个静态成员类继承自 Client,所以它的行为与作为超类子类的任何其他顶级类一样,包括它能够调用:“super.append();”。
  • 另外,关于第 2 项,我不同意你的看法。但同样,将静态成员类视为独立的顶级类是完全合适的。这包括静态成员类通过继承作为任何其他顶级超类的子类的关系。同样,我不相信您对静态嵌套类的概念有正确的看法;它们与内部类完全不同。
  • 最后,讨论 Client 是否是一个 DBTable 以及子类化是否提供了最好的模型是有效的。事实上,DBTable 所做的更多只是作为父级。它是一个抽象类,符合 Joshua Bloch 在“Effective Java, 2nd Ed”中描述的骨架实现模式。事实上,我数据库中的所有表都有继承自 DBTable 的数据模型类。我不得不说,到目前为止,这种设计对我来说非常灵活。
【解决方案2】:

我发现了问题。太丢脸了。作为我自己辩护的一部分,我会稍微迂回地回答我自己的问题。

我喜欢设计我的课程,让课程支持一个主题。与该主题相关的所有功能,我都喜欢尝试放在同一个类中。这对于数据库数据模型类特别有效,因为类的结构通常可以为其他数据库模型类重复。

我到底是什么意思?

嗯,这是我的 Client 类的“结构”。如您所见,它包含几个成员类:

+----------------------------+
|  CLIENT                    |
+---+------------------------+
    |  static EXPAND         |
    +------------------------+
    |  static GHOST          |
    +------------------------+
    |  static BUILDER        |
    +------------------------+
    |  static INQUISITOR     |
    +------------------------+
    |  static QUERYBUILDER   |
    +------------------------+
    |  static JDBCFactory    |
    +------------------------+

我非常喜欢这个设计。这意味着为我构建客户端对象的类可以与客户端类在同一个文件中,我可以使用半助记符“new Client.Builder()”来调用它,或者我可以创建一个构建 SQL 查询的对象对于带有“new Client.QueryBuilder()”的客户端对象。对象成为从 JDBC 结果集生成客户端对象的工厂的类可以用“new Client.JDBCFactory”等实例化。我非常喜欢这个。

缺点...是我有很多牙套。

而且...如果我不小心,我可能会输入一些以错误的上下文结尾的内容。在这种情况下,我在 EXPAND 成员类中键入 append() 方法的定义......实际上就在大括号之外,我将它键入到 CLIENT 的上下文中。

嗯,客户端已经有一个 append() 方法,所以 IDE 向我抱怨我试图覆盖同一个类中已经有一个 append() 方法的方法。

是的,Java 完全支持覆盖链。我的 IDE 或 JVM 没有任何问题……就我而言。再次感谢 @Robe 和其他人的意见。

【讨论】:

    猜你喜欢
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多