java.lang.Object的普通实例通常用于锁定/同步场景,这是公认的实践。

还有,为什么它是抽象的?因为它本身作为一个实例没有完全发挥作用吗?它真的能处理一些抽象的成员吗?我不这么认为。因此,从一开始就将其抽象化的论点是不存在的。所以不是。

以动物的经典层次结构为例,在这里你有一个抽象类 Animal,使 Animal类抽象的原因是因为 Animal 的一个实例实际上是一个“无效的”——因为缺少一个更好的词——動(即使它的所有方法都提供了一个基本的实现)。对于 Object来说,情况并非如此。首先,没有压倒性的理由让它变得抽象。

有时您需要一个没有自身状态的纯对象。虽然这些对象乍一看似乎无用,但它们仍有实用价值,因为每个对象都有不同的 身份。这在几种情况下都很有用,其中最重要的是锁定: 您希望协调两个线程。在 Java 中,通过使用一个将被用作锁的对象来实现这一点。物体不需要有任何状态,仅仅是它的存在就足以使它成为一把锁:

class MyThread extends Thread {
private Object lock;
public MyThread(Object l) { lock = l; }


public void run() {


doSomething();
synchronized(lock) {
doSomethingElse();
}
}
}


Object lock = new Object();
new MyThread(lock).start();
new MyThread(lock).start();

在本例中,我们使用一个锁来防止两个线程并发执行 doSomethingElse()

如果 Object 是抽象的,并且我们需要一个锁,那么我们必须对它进行子类化,而不需要添加任何方法或字段,这样我们就可以实例化 lock。

想一想,这里有一个双重的问题: 假设对象是抽象的,它会定义任何抽象的方法吗?我想答案是 没有。在这种情况下,将类定义为抽象类没有多大价值。

我可以想出几个 Object实例有用的例子:

  • 锁定和同步,就像您和其他评论者提到的那样。这可能是一种代码味道,但我一直看到 Object 实例以这种方式使用。
  • 作为 空对象,因为除了实例本身之外,equals总是返回 false。
  • 在测试代码中,尤其是在测试集合类时。有时用虚拟对象而不是 null填充集合或数组是最简单的。
  • 作为匿名类的基实例。例如:
    Object o = new Object() {...code here...}

它不抽象,因为每当我们创建一个新的类,它扩展了对象类,然后如果它是抽象的,你需要实现所有的对象类的方法,这是开销... 已经有方法实现在该类..。

它还意味着它可以在数组中实例化。在1.5天之前,这将允许您拥有通用的数据结构。这在某些平台上可能仍然适用(我认为是 J2ME,但我不确定)

Object 需要具体化的原因。

  1. 反思
    参见 Object.getClass ()

  2. 一般用途(预 Java5)

  3. 比较/输出
    请参见 Object.toString ()、 Object.equals ()、 Object.hashCode ()等

  4. 同步
    参见 Object.wait ()、 Object.tification ()等

即使有几个区域已经被替换/废弃,仍然需要一个具体的父类来为每个 Java 类提供这些特性。

Object 类用于反射,因此代码可以调用不确定类型的实例上的方法,即“ Object.class.getDeclaredMethod ()”。如果 Object 是抽象的,那么想要参与的代码必须实现所有的抽象方法,然后客户端代码才能对它们使用反射。

根据 Sun,抽象类是声明为抽象的类ーー它可能包含也可能不包含抽象方法。抽象类不能被实例化,但它们可以被子类化。,这也意味着你不能调用方法或访问抽象类的公共字段。

抽象根类的示例:

abstract public class AbstractBaseClass
{
public Class clazz;


public AbstractBaseClass(Class clazz)
{
super();
this.clazz = clazz;
}
}

我们的 AbstractBaseClass 的一个子类:

public class ReflectedClass extends AbstractBaseClass
{
public ReflectedClass()
{
super(this);
}


public static void main(String[] args)
{
ReflectedClass me = new ReflectedClass();
}
}

这将无法编译,因为在构造函数中引用“ This”是无效的,除非它调用同一类中的另一个构造函数。如果我把它改为:

   public ReflectedClass()
{
super(ReflectedClass.class);
}

但这仅仅是因为 RefectedClass 有一个父类(“ Object”) ,它是1)具体的,并且2)有一个字段来为其子类型存储类型。

一个更典型的反射例子是非静态成员函数:

public void foo()
{
Class localClass = AbstractBaseClass.clazz;
}

除非您将字段“ clazz”更改为静态,否则这将失败。对于 Object 的 class 字段,这样做不起作用,因为它应该是特定于实例的。Object 有一个静态类字段是没有意义的。

现在,我尝试了以下的改变,它的工作,但有点误导。它仍然需要将基类扩展到工作状态。

public void genericPrint(AbstractBaseClass c)
{
Class localClass = c.clazz;
System.out.println("Class is: " + localClass);
}


public static void main(String[] args)
{
ReflectedClass me = new ReflectedClass();
ReflectedClass meTwo = new ReflectedClass();


me.genericPrint(meTwo);
}

Java5之前的泛型(比如数组)是不可能的

Object[] array = new Object[100];
array[0] = me;
array[1] = meTwo;

需要构造实例作为占位符,直到接收到实际对象。

从我读到的所有内容来看,似乎 Object 不需要是具体的,实际上 应该是抽象的。

不仅不需要具体,而且在一些 更多的阅读之后,我确信 Object 没有的抽象性与基本继承模型相冲突——我们不应该允许具体类的抽象子类,因为子类应该只有 的功能。
显然,在 Java 中情况并非如此,我们有 Object的抽象子类。

没有 java.lang.Object的设计者告诉我们,我们只能根据观点来回答。有几个问题可以问清楚。

Object 的任何方法都可以从抽象中获益吗?

可以说,一些方法将从中受益。以 hashCode()equals()为例,如果它们都被抽象化,那么围绕这两个复杂性的挫折感可能会少得多。这将需要开发人员弄清楚他们应该如何实现它们,使它们应该保持一致变得更加明显(请参见有效的 Java)。然而,我更倾向于认为 hashCode()equals()clone()属于独立的、可选的抽象(即接口)。其他方法,如 wait()notify()finalize()等,都非常复杂,而且/或者是原生的,因此最好是已经实现了它们,并且不会从抽象中受益。

所以我猜答案是否定的,Object 的任何方法都不能从抽象中获益。

将 Object 类标记为抽象类是否有好处?

假设所有的方法都实现了,标记 Object 抽象的唯一效果就是它不能被构造(也就是说,new Object()是一个编译错误)。这有什么好处吗?我的观点是,术语“对象”本身就是抽象的(你能在你周围找到任何完全可以被描述为“对象”的东西吗?)因此它符合面向对象的范例。然而,在 纯粹主义者这一边是这样的。有人可能会说,强迫开发人员为任何具体的子类选择一个名称,即使是空的子类,也会导致代码更好地表达他们的意图。我认为,要在范式上完全成为 正确,对象应该标记为 abstract,但归根结底,没有真正的好处,这是一个设计偏好(实用主义与纯洁性)的问题。

使用普通对象进行同步的实践是否足够好,可以使其具体化?

其他许多答案都谈到构造一个在 synchronized()操作中使用的普通对象。虽然这可能已经是一个常见的和公认的做法,我不相信这将是一个足够好的理由,以防止对象是抽象的,如果设计师希望它是。其他的答案也提到了当我们想要同步某个对象的时候,我们必须声明一个 Object 的空子类,但是这并不成立——一个空子类可以在 SDK (java.lang.Lock或者其他什么)中提供,它可以在我们想要同步的任何时候被构造出来。这样做还有一个额外的好处,那就是创建一个更强有力的意向声明。

是否还有其他因素可能会因为对象的抽象而受到不利的影响?

从纯粹的设计角度来看,有几个领域可能会影响选择。不幸的是,我对它们的了解还不足以详细阐述。然而,如果这些因素中的任何一个对这一决定产生了影响,我都不会感到惊讶:

  • 表演
  • 保安
  • JVM 实现的简单性

还有其他原因吗?

有人提到它可能与反射有关。但是,在 Object 设计之后引入了反射。因此,它是否影响反射还没有定论——这不是原因。泛型也是如此。

还有一个名曲满天星就是 java.lang。对象是由人类设计的: 他们可能犯了错误,他们可能没有考虑到这个问题。没有一种语言是没有缺陷的,这个 就是其中之一,但是如果它是的话,它也不是一个很大的缺陷。我想我可以有把握地说,不缺乏雄心壮志,我不太可能参与设计这种广泛使用的技术的关键部分,尤其是一个持续了15年(?)而且仍然很强大,所以这不应该被认为是一种批评。

话虽如此,我还是会把它抽象化;-p

摘要
基本上,在我看来,这两个问题的答案都是“为什么 java.lang。物体混凝土?”或者(如果是这样的话)“为什么 java.lang。物体摘要?”是... “为什么不呢?”.

我认为它可能应该被声明为抽象的,但是一旦它被完成并被释放,就很难在不造成很多痛苦的情况下撤消它——参见 Java Language Spec 13.4.1:

“如果一个不抽象的类被更改为声明为抽象,那么试图创建该类的新实例的预先存在的二进制文件将在链接时抛出 InstantiationError,或者(如果使用了反射方法)在运行时抛出 InstantiationException; 因此不建议对广泛分布的类进行这种更改。”

我怀疑设计者不知道人们将来可能以何种方式使用对象,因此不想通过强制程序员在不必要的地方创建额外的类来限制程序员,例如互斥对象、键等。

我怀疑简短的答案是,在 Java 泛型出现之前,集合类丢失了类型信息。如果一个集合不是泛型的,那么它必须返回一个具体的 Object (并且在运行时向下转换为之前的任何类型)。

由于将具体类转换为抽象类会破坏二进制兼容性(如上面提到的那样) ,因此保留了具体的 Object 类。我想指出的是,在任何情况下,创建它都不是为了同步的唯一目的; 虚拟类也可以工作。

设计缺陷是从一开始就没有包括泛型。许多设计批评都是针对这个决定及其后果的。[哦,还有数组子类型规则。]

我认为到目前为止所有的答案都忘记了 Java 1.0是什么样子的。在 Java 1.0中,你不能创建一个匿名类,所以如果你只是为了某种目的需要一个对象(同步或者一个空占位符) ,你就必须为此声明一个类,然后一大堆代码就会为此目的拥有这些额外的类。只允许 Object 的直接实例化更直接。

当然,如果你今天在设计 Java,你可能会说每个人都应该这样做:

 Object NULL_OBJECT = new Object(){};

但是在1.0中这不是一个选项。

我不明白为什么大多数人似乎认为创建一个完全函数化的类是一个好主意,它以一种使用完全抽象的方式实现它的所有方法。
我宁愿问为什么要把它变得抽象?它是不是做了什么不该做的事?它是否缺少一些应该具有的功能?这两个问题的答案都是否定的,它本身就是一个完整的工作类,让它变得抽象只会导致人们实现空类。< br/>

public class UseableObject extends AbstractObject{}

UseableObject 从抽象 Object 继承而来,令人惊讶的是它可以实现,它没有添加任何功能,它存在的唯一原因是允许访问 Object 公开的方法。
我也不同意在“差”同步中使用。使用私有对象来同步访问比使用 sync (this)更安全,比使用 java util 并发的 Lock 类更安全、更容易使用。

在我看来,这只是一个简单的实用性问题。将类抽象化会剥夺程序员执行某些操作的能力,也就是说,实例化它。对于抽象类,没有什么是具体类做不到的。(你可以在其中声明抽象函数,但是在这种情况下,我们不需要有抽象函数。)因此,通过使它具体,你使它更加灵活。

当然,如果通过使其具体化而造成一些积极的伤害,那么“灵活性”将是一个缺点。但是我想不出使 Object 实例化会造成什么主动伤害。(“ instantiable”是一个词吗?随便啦。)我们可以讨论某人对原始 Object 实例的任何特定使用是否是一个好主意。但是,即使您可以说服我,我所见过的原始 Object 实例的每一次使用都是一个糟糕的主意,这仍然不能证明可能没有好的用途。所以,如果它不会伤害任何东西,而且它可能会有帮助,即使我们现在想不出一种方法,它实际上会有帮助,为什么要禁止它呢?