【问题标题】:Java: Rationale of the Object class not being declared abstractJava:Object 类未声明为抽象的基本原理
【发布时间】:2010-10-17 03:47:34
【问题描述】:

为什么不将java.lang.Object 类声明为抽象类?

当然,要使 Object 有用,它需要添加状态或行为,Object 类是一种抽象,因此它应该被声明为抽象...... 他们为什么选择不这样做?

【问题讨论】:

  • 如果.net已经决定了,这难道不就是点嫖娼吗?你真的觉得java会有不同的理由吗?嗯,我还是会回答的。
  • @Bill K:我想要与 Java 相关的实际推理。我不在乎.Net。一个理由也很好,但我仍然没有看到。
  • .net(或至少 C#)的理由是 C# 最初是 Java 的直接副本,所以他们只是按照 Java 的方式做。
  • 为什么应该对象被声明为抽象的?有时您需要一个类型无关紧要的占位符对象,而 Object 可以完美地工作。为什么要强迫人们为此创建自己的课程?

标签: java object specifications


【解决方案1】:

Object 是有用的,即使它没有任何特定的状态或行为。

一个例子是将其用作用于同步的通用保护:

public class Example {
    private final Object o = new Object();

    public void doSomething() {
        synchronized (o) {
            // do possibly dangerous stuff
        }
    }
}

虽然这个类的实现有点简单(这里不清楚为什么有一个显式对象很有用,你可以只声明方法synchronized)有几种情况是真的 有用。

【讨论】:

  • 如果您的类中有 3 个方法声明为同步,则所有 3 个方法只有一个锁,因此这 3 个方法中只有 1 个被同时调用。如果你的方法中有同步块,你可以使用超过 1 个对象作为锁。
  • 至少是在 java.util.concurrent 之前,或者除非你被困在 java 1.4 中
  • 如果 Object 是抽象的,为什么没有一个可以扩展 Object 的 Lock?
  • @Ande:是的,有些事情还是会这样做。例如,java.awt.Component 有“static class AWTTreeLock {}”和“static final Object LOCK = new AWTTreeLock();”
  • @TofuBeer:我有点希望在 1.0 上工作的人会发布“糟糕”。大声笑
【解决方案2】:

Ande,我认为你正在处理这个——双关语不是故意的——带有不必要的抽象程度。我认为这个(恕我直言)不必要的抽象级别是导致这里“问题”的原因。您可能是从数学理论方法来解决这个问题的,而我们中的许多人是从“程序员试图解决问题”的方法来解决这个问题的。我相信这种方法上的差异导致了分歧。

当程序员着眼于实用性以及如何实际实现某些东西时,很多时候您需要一些完全任意的对象,其实际实例完全不相关。它不能为空。我在另一篇文章的评论中给出的示例是 *Set 的实现(* == HashConcurrent 或选择类型),通常通过使用支持 *Map 并使用Map 键作为 Set。你经常不能使用null 作为Map 的值,所以通常的做法是使用一个静态的Object 实例作为值,它会被忽略并且永远不会使用。但是,需要一些非空占位符。

另一个常见用途是使用 synchronized 关键字,其中 some Object 需要同步,并且您希望确保您的同步项是完全私有的,以避免在不同类所在的情况下出现死锁无意中在同一个锁上同步。一个非常常见的习惯用法是分配一个private final Object 在类中用作锁。公平地说,从 Java 5 和 java.util.concurrent.locks.Lock 以及相关的新增内容开始,这个习语明显不太适用了。

从历史上看,在 Java 中让 Object 可实例化非常有用。您可以提出一个很好的观点,即通过对设计进行小的更改或对 API 进行小的更改,这将不再是必要的。你可能是正确的。

是的,API 可以提供一个扩展 ObjectPlaceholder 类,而无需添加任何内容,用作上述目的的占位符。但是——如果你扩展Object 但什么都不添加,那么除了允许Object 是抽象的之外,类中的值是什么?在数学上,理论上,也许人们可以找到一个价值,但从实用上讲,这样做会增加什么价值?

在编程中有时您需要一个对象、some 对象、any 不为空的具体对象,您可以通过== 和/或.equals(),但您只是不需要此对象的任何其他功能。它的存在只是作为一个唯一的标识符,否则绝对什么都不做。 Object 完美地满足了这个角色,并且(恕我直言)非常干净。

我猜 thisObject 未被声明为抽象的部分原因:它不被声明为直接有用。

【讨论】:

  • 我相信可实例化的对象允许程序员将 OOP 理解为一种建模技术时出现惯用错误。如果它是一个错误,它现在被用作一个特性,如果它最初是不允许的,那么更好的方法现在将是 Java 的惯用方法。
  • +1,因为虽然我们可能不同意,但我仍然同意 mmyers。 :p
  • @Ande:我完全同意这是抽象的对象,只需对 API 进行一些小的更改就足以完全替换可实例化的对象。如果由我决定,我会删除 Java 中的每个对象也是一个锁,并且需要锁(或派生)来进行同步。
【解决方案3】:

Object 是否指定了扩展它的类必须实现的方法才能有用?不,因此它不必是抽象的。

抽象类的概念具有明确定义的含义,不适用于 Object。

【讨论】:

  • 您的“因此”在逻辑上与您前面的陈述不相符,并且抽象类的概念具有适用于 Object 的明确定义。
  • @Ande:你怎么看?正如其他人所展示的,对象本身是有用的。你怎么认为它一定是抽象的?
  • @Ande:抽象表示一个类,其定义不完整,无法创建该类的实例。这显然不适用于 Object,即使创建实例没有用。其他人指出了它有用的情况。
  • @Kris:摘要应该定义一个抽象;一个对象应该被声明为抽象的,因为你试图概念化的现实世界环境不能实例化没有潜力的非实质性物质。
【解决方案4】:

您可以实例化Object 用于同步锁:

Object lock = new Object();

void someMethod() {
  //safe stuff
  synchronized(lock) {
     //some code avoiding race condition
  }
}

void someOtherMethod() {
  //safe code
  synchronized(lock) {
    //some other stuff avoiding race condition
  }
}

【讨论】:

    【解决方案5】:

    我不确定这是否是原因,但它允许(或允许,因为现在有更好的方法可以做到这一点)将对象用作锁:

    Object lock = new Object();
    
    ....
    
    
    synchronized(lock)
    {
    }
    

    【讨论】:

      【解决方案6】:

      Object 怎么比 null 更令人反感?

      它是一个很好的位置标记(无论如何都和 null 一样好)。

      另外,我不认为在没有抽象方法的情况下将对象抽象为一个好的设计。

      我并不是说 null 是自切片面包以来最好的东西——我前几天读了一篇“发明家”的文章,讨论了拥有 null 概念的成本/价值......(我什至没有认为 null 是可以发明的!我猜某个地方的某个人可能会声称他发明了零……)只是能够实例化 Object 并不比能够传递 null 更糟糕。

      【讨论】:

      • 在某种意义上,非抽象对象的实例化是 null 的实例化,但更糟糕的是,因为我看到了使用它的论据。它是一个没有实质和能力的东西,实际上也许它可以用来表示暗物质,嗯。
      • 我已经看到当没有现有的对象实例有意义时,它被用作简单的锁。为什么这会给您带来如此大的压力可能是一个更好的问题...在每种语言中都有更多令人震惊的问题。
      • “我猜某个地方的某个人可能会声称他发明了零。”零的概念实际上是被发明的。来自维基百科:“零作为数字而不仅仅是分离符号的概念归因于印度,到公元 9 世纪,印度使用零进行了实际计算”
      • @Ande:对象不是空值。这是一个零维点,是你可以实例化的最小的东西。这与 null 有很大不同。为什么可以实例化 Object 让您感到困扰,而能够实例化 Object 显然如此有用?
      • @Eddie:列出的用途并不排除它们被应用于任何其他实例化的对象扩展。
      【解决方案7】:

      您永远不知道何时需要使用简单的对象作为占位符。可以把它想象成数字系统中有一个零(而 null 对此不起作用,因为 null 表示没有数据)。

      【讨论】:

      • 虽然有一些用于计数的原语。为什么要将对象的概念拖入不值得使用的情况?
      • 一开始 Java 并没有原语(我认为这对这个特定的讨论并不重要)。
      • @Ande:艾伦丹尼尔斯不是在谈论计数。他在谈论使用占位符。原始人不会做这项工作,因为他们是原始人。
      • @Eddie:占位符有什么用?确切地?数字、值、符号?
      • @Ande,Set( = 某种类型的 Set)的(常见)实现是使用 Map 并将 Object 作为值,使用键作为集合。您必须将 *something 作为值,即 Object。占位符。有些地方你不能使用 null,但必须使用一些任意的 Object。占位符。
      【解决方案8】:

      应该有一个将类抽象化的理由。一种是防止客户端实例化类并强制他们只使用子类(无论出于何种原因)。另一个是如果您希望通过提供抽象方法将其用作接口,子类必须实现这些方法。也许,Java 的设计者没有看到这样的原因,所以java.lang.Object 仍然是具体的。

      【讨论】:

        【解决方案9】:

        Guava 一如既往地提供帮助:http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html 这里的东西可用于从代码中杀死“非空占位符”的空值/对象实例。

        这里有完全不同的问题:

        • 他们为什么不将 Object 抽象化?
        • 如果他们决定在未来的版本中将其抽象化,会带来多大的灾难?

        【讨论】:

          【解决方案10】:

          我将提出另一个原因,即我发现 Object 对自己进行实例化很有用。我创建了一个包含多个插槽的对象池。这些槽可以包含许多对象中的任何一个,所有对象都继承自抽象类。但是我在池中放什么来代表“空”。我可以使用null,但就我的目的而言,确保每个插槽中始终有一些对象更有意义。我无法实例化要放入其中的抽象类,我也不想这样做。所以我可以创建一个抽象类的具体子类来表示“不是一个有用的 foo”,但是当使用 Object 的实例时这似乎是不必要的......实际上更好,因为它清楚地说明了插槽中的内容没有功能。所以当我初始化我的池时,我通过创建一个对象来分配给每个插槽作为池的初始条件。

          我同意最初的 Java 工作人员将 Placeholder 对象定义为 Object 的具体子类,然后将 Object 抽象为抽象对象可能是有意义的,但这并没有让我误会他们所做的一切都是按照他们的方式进行的。然后我会使用Placeholder 代替Object

          【讨论】:

            猜你喜欢
            • 2020-04-12
            • 2021-06-10
            • 2013-05-10
            • 1970-01-01
            • 1970-01-01
            • 2014-02-26
            • 1970-01-01
            • 2015-02-28
            • 2015-11-24
            相关资源
            最近更新 更多