覆盖非抽象方法是好的做法吗?

Is it good practice to override non abstract methods?

我有一种情况需要修改 super class 方法以具有 subclass 特定逻辑,但所有其他 subclasses 的方法逻辑相同.

我有两个选择:

1) 使方法抽象化,并为每个除了我关心的子class 重复相同的代码。

2) 在我想要更改逻辑的相关子 class 中重写非抽象方法。

在 Java 中重写非抽象方法是一种好习惯吗?以及在概念上 b/w 覆盖非抽象方法与抽象方法的区别是什么。

在某种程度上,这是风格问题。

这是一种常见的做法 - 但也有人告诉您任何方法都不应有多个实现。这些人声称继承层次结构中的多个实现会导致难以调试的代码——因为您必须非常小心地确定实际调用此类方法的哪个版本。

当这些方法被其他方法大量使用时,您很容易失去全局 - 突然间预测某些代码正在做什么变得复杂 - 因为在某些子 class es.

需要理解的 key 事情:class X 中某些方法 foo() 的 "single" @Override 很好,而且很常见,好的做法。但是在 X 的子 class 中重写相同的 foo() 再次 - 这会很快导致各种问题。

换句话说:重新实现非抽象方法应该小心。如果它使您的代码更难理解,请寻找其他解决方案。比如:基础 class 有一个固定的(最终的)方法做事——并且那个方法调用其他 abstract 方法来完成它的工作。示例:

public abstract class Base {
  public final int doSomething() {
    String tmp = foo();
    int result = bar(tmp);
    return result * result;
  }
  public abstract String foo();
  public abstract int bar(String str);

如所写:在这里你可以看到 实现 是 "fixed" 因为 doSomething() 是最终的 - 但所需的 "ingredients" 可以(必须) 在每个子 class.

中被覆盖

Is it a good practice in Java to override a non-abstract method?

是的。 (但是,请确保您没有违反 Liskov Substitution Principle(指 SO 现有 post),这告诉子 classes 不应该破坏父 class 类型定义。例如, walk ()Animal 覆盖的方法 class 应该执行(有行为)步行,它不应该执行飞行或其他东西。)

我还建议通过 SOLID Principle 了解设计原理。

and what would be the difference conceptually b/w overriding non-abstract vs abstract methods.

AFAIK 没有区别。但是,需要明确的是,抽象方法不包含任何实现,您必须覆盖非抽象方法可以被覆盖的地方。

在我想要更改逻辑的相关子class 中重写非抽象方法 - 是的

例如: 如果您考虑 Object class 中的 toString() 和 hashCode() 两种方法都是非抽象方法,但通常建议在我们的 subclasses.

中重写这些方法

因为如果我要执行我的逻辑而不是超class逻辑需要重写使用,建议在这种情况下重写

只要不违反 Liskov Subsitution principle:

,重写非抽象方法是完全可以的,并且是常用的做法

Liskov's principle imposes some standard requirements on signatures

  • Contravariance of method arguments in the subtype.
  • Covariance of return types in the subtype.
  • No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.

In addition to the signature requirements, the subtype must meet a number of behavioral conditions.

  • Preconditions cannot be strengthened in a subtype.
  • Postconditions cannot be weakened in a subtype.
  • Invariants of the supertype must be preserved in a subtype.
  • History constraint (the "history rule"). Objects are regarded as being modifiable only through their methods (encapsulation). Because subtypes may introduce methods that are not present in the supertype, the introduction of these methods may allow state changes in the subtype that are not permissible in the supertype. The history constraint prohibits this.

只要该方法在被覆盖后仍然遵守约定,就不会混淆新实现的功能。该方法的新实现仍应遵守与被覆盖之前的实现相同的约定。