【问题标题】:Reuse superclass static fields重用超类静态字段
【发布时间】:2012-08-27 10:49:21
【问题描述】:

我有这个类声明

abstract class  A {
    protected static String message = "Hello";
}

我希望这个字段传播到子类,以避免在所有子类中输入protected static String message = "Whatever";(每个子类中这个静态字段的值不同)。

我知道这行不通:

class B extends A {

    static {
        message = "Blablabla";
    }
}

因为它实际上会修改Amessage,因为静态字段/方法不会被继承。我想知道是否有其他方法可以做到这一点,或者我是否必须重写每个子类的静态字段。

【问题讨论】:

  • 是什么让您无法编写非静态 protected String getMessage() 模板方法(在 A 中可以是抽象的或具体的,取决于您是否要允许默认行为)
  • 如果您希望它少于 4 个字,您期望什么样的解决方案?
  • 这不是四个字。这是关于代码重用,这 - 据说 - 是使用 OOP 的好处之一。

标签: java inheritance static


【解决方案1】:

我建议使用被每个子类覆盖的受保护方法 getMessage() 而不是静态字段。

class B extends A {
    @Override
    protected String getMessage() {
        return "Blablabla";
    }
}

【讨论】:

  • 谢谢。因为我真的不喜欢在方法中使用硬编码字符串,所以这个答案基本上与 Keppil 的答案相同(检查我在那里制作的 cmets)。
【解决方案2】:

没有直接的方法。

您可以考虑使用一些将 Class 对象映射到消息的实用程序类。这将帮助您使用通用方法处理基于this.getClass() 的消息。

【讨论】:

  • 这个问题是一个例子。我在基类上有几个字段。所以它仍然是同样的问题,因为我需要定义一个包含这些字段的类以将其映射到 Class 实例,这使我回到起点问题。无论如何谢谢:)
  • @m0skit0 当然,你需要更多的编码。为了使它看起来像带有静态部分的示例,您可以在任何类的此部分中使用 register(B.class, "Whatever") 之类的东西。另一方面,这种方法的优点包括只为每个类存储一个引用(而不是为每个对象存储一个引用以防有其他建议)。
  • 是的,但正如我所说,可能第二个参数(“Whatever”)必须是一个完整的对象,而不仅仅是一个字符串,所以我再次回到静态继承的问题: )
  • 好吧,我不确定我是否理解您再次回到静态继承问题的意思。我的方法根本不使用继承。例如,当你想为一个班级分配一条消息时,你使用register,当你想为一个班级获取一条消息时,你只需使用getMessage。这些方法是在另一个不使用继承的辅助类中定义的,它只是从类到消息的映射。此外,这个类是一个单例。
【解决方案3】:

这种情况下我通常会创建一个get方法:

abstract class  A {
    private static final String DEFAULT_MESSAGE = "Hello";
    protected String getMessage() {
        return DEFAULT_MESSAGE;
    }
}

这使得在我想要的子类中覆盖消息变得容易。

【讨论】:

  • 谢谢,但实际上什么也没解决,因为这样我仍然必须在所有子类中写private static final String DEFAULT_MESSAGE = "Whatever";,这是主要问题。
  • @m0skit0:不,你不会,你为什么会?
  • 嗯?正如我所说,我希望每个子类中都有不同的 DEFAULT_MESSAGE 值。
  • @m0skit0:好的,那么您需要在每个要更改的子类中覆盖getMessage()。静态默认消息只是一种样式选择,如果您愿意,可以跳过该行并直接编写消息。
  • 我其实更喜欢你的风格,但正如我所见,使用静态字段确实没有令人满意的解决方案。然后我将使用实例字段。感谢您的宝贵时间!
【解决方案4】:

静态字段和方法继承的 - 作为一名 C 程序员,我被告知将它们视为类似于“全局”变量,命名为类(并具有私有/受保护的限制) .

从您的第一个 sn-p 开始,B.message 将是“Hello”。

你必须做到这一点

public class A {
  protected String message = "Hello";
}

public class A {
  private static String message = "Hello";
}

public class B {
  private static String message = "Howdy";
}

【讨论】:

  • 这没有用,因为正如我在 OP 中所说,我不想重写所有子类中的字段声明。第一个 sn-p 也不起作用,因为我必须初始化所有对象,恕我直言,这是无用的工作,因为我已经知道该类的所有实例都具有这样的值。而且我认为 Java 静态字段/方法在技术上不是继承的,而是 可见 因为如果我这样做 B.A 我实际上指的是 A.A
  • 也就是说,并且看起来没有有用的方法可以作为静态字段执行此操作,我可能会使用您的第一个示例并覆盖子​​类构造函数中的值。谢谢!
  • A.A => B.A 继承。有趣的是,有时我们付出所有这些努力是为了节省一点点努力,这只是出于原则——你有时需要退后一步,正确看待它。第二个 sn-p 是一种常见的模式 - 在每个类的开头都有类似的行,例如:“private static final Logger logger = LoggerFactory.getLogger(MyClass.class);”
  • 是的,但是普通并不意味着它很好;)我也有那种 Logger 的东西,但你不认为如果你能继承它会更容易、更干净、更有用这个来自超类的静态最终记录器?
  • 但是你的应用程序中只有一个记录器实例,并且要确定哪个类正在编写每个日志事件会更加困难。
【解决方案5】:

一个方面会让你实现你想做的事情吗?您可以从一个地方逐个类地配置/管理具有特定名称的方法的返回值。 ...这仍然比在每个子类中复制相同的样板“私有静态 ...”要多。

【讨论】:

  • 你能扩展这个答案吗?我不完全明白你的意思。我的理解类似于 tcb 的回答。
猜你喜欢
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多