为什么这个java.lang.Object
类没有被声明为 abstract ?
当然,要使 Object 有用,它需要添加状态或行为,Object 类是一种抽象,因此它应该被声明为抽象...... 为什么他们选择不这样做?
为什么这个java.lang.Object
类没有被声明为 abstract ?
当然,要使 Object 有用,它需要添加状态或行为,Object 类是一种抽象,因此它应该被声明为抽象...... 为什么他们选择不这样做?
即使AnObject
没有任何特定于它的状态或行为,它也是有用的。
一个例子是将其用作用于同步的通用防护:
public class Example {
private final Object o = new Object();
public void doSomething() {
synchronized (o) {
// do possibly dangerous stuff
}
}
}
虽然这个类的实现有点简单(这里不清楚为什么有一个显式对象很有用,你可以只声明方法synchronized
),但在很多情况下它确实很有用。
Ande,我认为你正在处理这个——双关语不是故意的——带有不必要的抽象程度。我认为这个(恕我直言)不必要的抽象级别是造成“问题”的原因。您可能是从数学理论方法来处理这个问题,而我们中的许多人是从“程序员试图解决问题”的方法来处理这个问题的。我相信这种方法上的差异导致了分歧。
当程序员着眼于实用性以及如何实际实现某些东西时,很多时候您需要一些完全任意的对象,其实际实例完全不相关。它不能为空。我在另一篇文章的评论中给出的示例是*Set
(*
==Hash
或Concurrent
或选择类型)的实现,这通常通过使用支持*Map
并将Map
键用作 Set 来完成。你经常不能使用null
作为Map
值,所以通常的做法是使用静态Object
实例作为值,它会被忽略并且永远不会使用。但是,需要一些非空占位符。
另一个常见的用途是synchronized
关键字需要 Object
同步,并且您希望确保您的同步项是完全私有的,以避免不同类无意地在同一个锁上同步的死锁。一个非常常见的习惯用法是分配一个private final Object
在类中使用的锁。公平地说,从 Java 5 和java.util.concurrent.locks.Lock
相关的新增内容开始,这个习语明显不太适用。
Object
从历史上看,可实例化在 Java 中非常有用。您可以提出一个很好的观点,即只要对设计进行微小的更改或对 API 进行少量更改,就不再需要这样做了。你可能是正确的。
是的,API 可以提供一个Placeholder
扩展类Object
而不添加任何东西,用作上述目的的占位符。但是——如果你在扩展Object
但什么都不添加,那么除了允许Object
抽象之外,类中的价值是什么?在数学上,理论上,也许人们可以找到一个价值,但从实用上讲,这样做会增加什么价值?
在编程中,有时您需要一个对象、某个对象、任何非空的具体对象,您可以通过==
and/or进行比较.equals()
,但您不需要该对象的任何其他功能。它的存在只是作为一个唯一的标识符,否则绝对什么都不做。 Object
完美地满足了这个角色,并且(恕我直言)非常干净。
我猜这就是为什么Object
没有被声明为抽象的部分原因:它不被声明是直接有用的。
Object 是否指定了扩展它的类必须实现的方法才能有用?不,因此它不必是抽象的。
抽象类的概念具有明确定义的含义,不适用于 Object。
您可以实例化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
}
}
我不确定这是不是原因,但它允许(或允许,因为现在有更好的方法可以做到这一点)将对象用作锁:
Object lock = new Object();
....
synchronized(lock)
{
}
Object 如何比 null 更令人反感?
它是一个很好的位置标记(无论如何都和 null 一样好)。
另外,我不认为在没有抽象方法的情况下将对象抽象化不是一个好的设计。
我并不是说 null 是自切片面包以来最好的东西——前几天我读了一篇“发明家”的文章,讨论了拥有 null 概念的成本/价值……(我什至不认为 null 是可发明!我猜某个地方的某个人可能会声称他发明了零……)只是能够实例化 Object 并不比能够传递 null 更糟糕。
你永远不知道什么时候你可能想使用一个简单的对象作为占位符。把它想象成在数字系统中有一个零(而 null 对此不起作用,因为 null 表示没有数据)。
将类抽象化应该是有原因的。一种是防止客户端实例化类并强制他们只使用子类(无论出于何种原因)。另一个是如果您希望通过提供抽象方法将其用作接口,子类必须实现这些方法。也许,Java 的设计者没有看到这样的原因,所以java.lang.Object
仍然是具体的。
与往常一样,Guava 提供帮助:使用http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html 这里的东西可以用来杀死空值/对象实例代码中的“非空占位符”。
这里有完全独立的问题:
我将提出另一个原因,即我发现 Object 对于自己实例化很有用。我创建了一个包含多个插槽的对象池。这些槽可以包含许多对象中的任何一个,所有对象都继承自抽象类。但是我在池中放什么来代表“空”。我可以使用null
,但出于我的目的,确保每个插槽中始终有一些对象更有意义。我无法实例化要放入其中的抽象类,我也不想这样做。所以我可以创建我的抽象类的一个具体子类来表示“不是一个有用的 foo”,但是当使用 Object 的实例时这似乎是不必要的......实际上更好,因为它清楚地说明了插槽中的内容没有功能。因此,当我初始化我的池时,我通过创建一个对象来分配给每个插槽作为池的初始条件。
Placeholder
我同意最初的 Java 工作人员将对象定义为 的具体子类Object
,然后将其抽象化,这可能是有道理的Object
,但他们的做法并没有让我感到错误。然后我会用Placeholder
它来代替Object
.