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