为什么 java.lang.Object 不是抽象的?
可能的重复:
Java:Object 类未声明为抽象的基本原理< /a>
为什么 Object 类(Java 中所有类的基类)不是抽象类?
我已经有这个问题很长时间了,在这里问这个问题纯粹是出于好奇,仅此而已。我的代码或任何人的代码中没有任何内容被破坏,因为它不是抽象的,但我想知道为什么他们将其具体化?
为什么有人想要这个对象类的“实例”(而不是它的存在,又名引用)?一种情况是一个糟糕的同步代码,它使用对象的实例进行锁定(至少我曾经这样使用过一次......我的错)。
Object 类的“实例”有任何实际用途吗?它的实例化如何适合 OOP?如果他们将其标记为抽象(当然是在提供其方法的实现之后),会发生什么?
Possible Duplicate:
Java: Rationale of the Object class not being declared abstract
Why is the Object class, which is base class of 'em all in Java, not abstract?
I've had this question for a really really long time and it is asked here purely out of curiosity, that's all. Nothing in my code or anybody's code is breaking because it is not abstract, but I was wondering why they made it concrete?
Why would anyone want an "instance" (and not its presence a.k.a. Reference) of this Object class? One case is a poor synchronization code which uses the instance of an Object for locking (at least I used it this way once.. my bad).
Is there any practical use of an "instance" of an Object class? And how does its instantiation fit in OOP? What would have happened if they had marked it abstract (of course after providing implementations to its methods)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
如果没有
java.lang.Object
的设计者告诉我们,我们必须根据意见来回答。可以提出一些问题,这可能有助于解决问题。对象的任何方法都会从抽象中受益吗?
可以说,某些方法会从中受益。以
hashCode()
和equals()
为例,如果这两者都被抽象化,那么围绕这两者的复杂性可能会少很多挫败感。这将要求开发人员弄清楚他们应该如何实现它们,从而更明显地表明它们应该保持一致(请参阅Effective Java)。但是,我更认为hashCode()
、equals()
和clone()
属于单独的、可选的抽象(即接口)。其他方法,wait()
、notify()
、finalize()
等足够复杂并且/或者是原生的,所以它是最好它们已经实现,并且不会从抽象中受益。所以我猜答案是否定的,对象的任何方法都不会从抽象中受益。
将 Object 类标记为抽象会有好处吗?
假设所有方法都已实现,标记 Object 抽象的唯一效果是无法构造它(即
new Object()< /code> 是一个编译错误)。这会有好处吗?我认为“对象”这个术语本身就是抽象的(你能在你周围找到任何可以完全描述为“对象”的东西吗?),所以它符合面向对象的范式。然而,它是在纯粹主义者方面。有人可能会说,强迫开发人员为任何具体子类(甚至是空子类)选择一个名称,将导致代码更好地表达他们的意图。我认为,就范式而言,要完全正确,对象应该被标记为
抽象
,但归根结底,没有真正的好处,这只是一个问题设计偏好(实用主义与纯粹性)。使用普通对象进行同步的做法是否足以使其具体化?
许多其他答案都讨论了构造一个在
synchronized() 中使用的普通对象代码>操作。虽然这可能是一种常见且被接受的做法,但我认为如果设计者希望它成为抽象的,那么这并不是一个足够好的理由来阻止对象成为抽象的。其他答案提到了每当我们想要在某个对象上同步时,我们都必须声明一个空的 Object 子类,但这并不成立 - SDK 中可以提供一个空的子类(
java.lang.Lock
或其他),可以在我们想要同步的任何时候构造它。这样做还有一个额外的好处,那就是创建更强有力的意向声明。是否有任何其他因素可能因使对象抽象而受到不利影响?
从纯粹的设计角度来看,有几个领域可能会影响选择。不幸的是,我对它们了解不够,无法对其进行扩展。然而,如果其中任何一个对决定产生影响,我不会感到惊讶:
还有其他原因吗?
有人提到它可能与反射有关。然而反射是在Object设计之后引入的。所以它是否影响反射是没有意义的——这不是原因。对于仿制药也是如此。
还有令人难忘的一点,java.lang.Object是人类设计的:他们可能犯了错误,他们可能没有考虑到这个问题。没有一种语言是没有缺陷的,这可能就是其中之一,但如果是的话,它也不是一个大缺陷。我想我可以有把握地说,我不太可能参与设计如此广泛使用的技术的关键部分,尤其是持续了 15(?) 年并且仍然强劲的技术,所以这不应被视为批评。
话虽如此,我会把它变得抽象;-p
摘要
基本上,据我所知,两个问题的答案“为什么 java.lang.Object 是具体的?”或者(如果是这样的话)“为什么 java.lang.Object 是抽象的?”是...“为什么不呢?”。
Without the designers of
java.lang.Object
telling us, we have to base our answers on opinion. There's a few questions which can be asked which may help clear it up.Would any of the methods of Object benefit from being abstract?
It could be argued that some of the methods would benefit from this. Take
hashCode()
andequals()
for instance, there would probably have been a lot less frustration around the complexities of these two if they had both been made abstract. This would require developers to figure out how they should be implementing them, making it more obvious that they should be consistent (see Effective Java). However, I'm more of the opinion thathashCode()
,equals()
andclone()
belong on separate, opt-in abstractions (i.e. interfaces). The other methods,wait()
,notify()
,finalize()
, etc. are sufficiently complicated and/or are native, so it's best they're already implemented, and would not benefit from being abstracted.So I'd guess the answer would be no, none of the methods of Object would benefit from being abstract.
Would it be a benefit to mark the Object class as abstract?
Assuming all the methods are implemented, the only effect of marking Object abstract is that it cannot be constructed (i.e.
new Object()
is a compile error). Would this have a benefit? I'm of the opinion that the term "object" is itself abstract (can you find anything around you which can be totally described as "an object"?), so it would fit with the object-oriented paradigm. It is however, on the purist side. It could be argued that forcing developers to pick a name for any concrete subclass, even empty ones, will result in code which better expresses their intent. I think, to be totally correct in terms of the paradigm, Object should be markedabstract
, but when it comes down to it, there's no real benefit, it's a matter of design preference (pragmatism vs. purity).Is the practice of using a plain Object for synchronisation a good enough reason for it to be concrete?
Many of the other answers talk about constructing a plain object to use in the
synchronized()
operation. While this may have been a common and accepted practice, I don't believe it would be a good enough reason to prevent Object being abstract if the designers wanted it to be. Other answers have mentioned how we would have to declare a single, empty subclass of Object any time we wanted to synchronise on a certain object, but this doesn't stand up - an empty subclass could have been provided in the SDK (java.lang.Lock
or whatever), which could be constructed any time we wanted to synchronise. Doing this would have the added benefit of creating a stronger statement of intent.Are there any other factors which could have been adversely affected by making Object abstract?
There are several areas, separate from a pure design standpoint, which may have influenced the choice. Unfortunately, I do not know enough about them to expand on them. However, it would not suprise me if any of these had an impact on the decision:
Could there be other reasons?
It's been mentioned that it may be in relation to reflection. However, reflection was introduced after Object was designed. So whether it affects reflection or not is moot - it's not the reason. The same for generics.
There's also the unforgettable point that java.lang.Object was designed by humans: they may have made a mistake, they may not have considered the question. There is no language without flaws, and this may be one of them, but if it is, it's hardly a big one. And I think I can safely say, without lack of ambition, that I'm very unlikely to be involved in designing a key part of such a widely used technology, especially one that's lasted 15(?) years and still going strong, so this shouldn't be considered a criticism.
Having said that, I would have made it abstract ;-p
Summary
Basically, as far as I see it, the answer to both questions "Why is java.lang.Object concrete?" or (if it were so) "Why is java.lang.Object abstract?" is... "Why not?".
java.lang.Object
的普通实例通常用于锁定/同步场景,这是公认的做法。另外 - 它是抽象的原因是什么?因为它作为一个实例本身并不能完全发挥作用?它真的可以与一些抽象成员相关吗?不这么认为。因此,首先将其抽象化的论据是不存在的。所以事实并非如此。
以经典的动物层次结构为例,其中有一个抽象类
Animal
,将Animal
类抽象化的原因是因为 Animal 的实例实际上是“无效”的 -由于缺乏更好的词 - 动物(即使它的所有方法都提供了基本实现)。对于Object
来说,情况根本不是这样。首先并没有什么压倒性的案例让它变得抽象。Plain instances of
java.lang.Object
are typically used in locking/syncronization scenarios and that's accepted practice.Also - what would be the reason for it to be abstract? Because it's not fully functional in its own right as an instance? Could it really do with some abstract members? Don't think so. So the argument for making it abstract in the first place is non-existent. So it isn't.
Take the classic hierarchy of animals, where you have an abstract class
Animal
, the reasoning to make theAnimal
class abstract is because an instance of Animal is effectively an 'invalid' -by lack of a better word- animal (even if all its methods provide a base implementation). WithObject
, that is simply not the case. There is no overwhelming case to make it abstract in the first place.从我读到的所有内容来看,
Object
不需要是具体的,事实上应该是抽象的。不仅不需要具体,而且经过一些 更多阅读 我相信
Object
not 是抽象的与基本继承模型相冲突 - 我们不应该允许具体类的抽象子类,因为子类应该只添加功能。显然,Java 中的情况并非如此,我们有
Object
的抽象子类。From everything I've read, it seems that
Object
does not need to be concrete, and in fact should have been abstract.Not only is there no need for it to be concrete, but after some more reading I am convinced that
Object
not being abstract is in conflict with the basic inheritance model - we should not be allowing abstract subclasses of a concrete class, since subclasses should only add functionality.Clearly this is not the case in Java, where we have abstract subclasses of
Object
.我可以想到
Object
实例很有用的几种情况:equals
将始终返回 false,除了实例本身。null
填充集合或数组是最简单的。Object o = new Object() {...此处代码...}
I can think of several cases where instances of
Object
are useful:equals
will always return false, except on the instance itself.null
s.Object o = new Object() {...code here...}
我认为它可能应该被声明为抽象的,但是一旦完成并发布,就很难在不造成很大痛苦的情况下撤消 - 请参阅 Java 语言规范 13.4.1:
“如果一个不是抽象的类被更改为声明为抽象,则尝试创建该类的新实例的预先存在的二进制文件将在链接时抛出 InstantiationError ,或者(如果使用反射方法)在运行时抛出 InstantiationException ,因此不建议对广泛分布的类进行此类更改; ”。
I think it probably should have been declared abstract, but once it is done and released it is very hard to undo without causing a lot of pain - see Java Language Spec 13.4.1:
"If a class that was not abstract is changed to be declared abstract, then preexisting binaries that attempt to create new instances of that class will throw either an InstantiationError at link time, or (if a reflective method is used) an InstantiationException at run time; such a change is therefore not recommended for widely distributed classes."
有时您需要一个没有自己状态的普通对象。虽然这些物体乍一看似乎毫无用处,但它们仍然有用,因为每个物体都有不同的身份。 Tnis 在多种情况下很有用,其中最重要的是锁定:您想要协调两个线程。在 Java 中,您可以通过使用一个将用作锁的对象来实现这一点。对象不需要有任何状态,它的存在就足以成为一个锁:
在这个例子中,我们使用锁来防止两个线程同时执行
doSomethingElse()
如果对象是抽象的,并且我们如果需要一个锁,我们必须将其子类化,而不添加任何方法或字段,以便我们可以实例化锁。
想想看,这里有一个双重问题:假设 Object 是抽象的,它会定义任何抽象方法吗?我想答案是否。在这种情况下,将类定义为抽象类没有太大价值。
From time to time you need a plain Object that has no state of its own. Although such objects seem useless at first sight, they still have utility since each one has different identity. Tnis is useful in several scenarios, most important of which is locking: You want to coordinate two threads. In Java you do that by using an object that will be used as a lock. The object need not have any state its mere existence is enough for it to become a lock:
In this example we used a lock to prevent the two threads from concurrently executing
doSomethingElse()
If Object were abstract and we needed a lock we'd have to subclass it without adding any method nor fields just so that we can instantiate lock.
Coming to think about it, here's a dual question to yours: Suppose Object were abstract, will it define any abstract methods? I guess the answer is No. In such circumstances there is not much value to defining the class as abstract.
我不明白为什么大多数人似乎相信创建一个功能齐全的类,以使用完整的抽象方式实现其所有方法将是一个好主意。
我更想问为什么要抽象?它做了不该做的事吗?它是否缺少一些应有的功能?这两个问题都可以用“否”来回答,它本身就是一个完全工作的类,使其抽象只会导致人们实现空类。
UseableObject 继承自抽象 Object,令人惊讶的是它可以实现,它没有添加任何内容功能及其存在的唯一原因是允许访问对象公开的方法。
另外,我不同意在“差”同步中使用。使用私有对象来同步访问比使用synchronize(this)更安全,并且比java util并发中的Lock类更安全且更易于使用。
I don't understand why most seem to believe that making a fully functional class, which implements all of its methods in a use full way abstract would be a good idea.
I would rather ask why make it abstract? Does it do something it shouldn't? is it missing some functionality it should have? Both those questions can be answered with no, it is a fully working class on its own, making it abstract just leads to people implementing empty classes.
UseableObject inherits from abstract Object and surprise it can be implemented, it does not add any functionality and its only reason to exist is to allow access to the methods exposed by Object.
Also I have to disagree with the use in "poor" synchronisation. Using private Objects to synchronize access is safer than using synchronize(this) and safer as well as easier to use than the Lock classes from java util concurrent.
在我看来,这里有一个简单的实用性问题。将类抽象化会剥夺程序员执行某些操作(即实例化它)的能力。对于抽象类来说,没有什么是对于具体类不能做的。 (嗯,你可以在其中声明抽象函数,但在这种情况下我们不需要抽象函数。)因此,通过使其具体化,你可以使其更加灵活。
当然,如果具体化会造成一些积极的损害,那么“灵活性”将是一个缺点。但我想不出使对象可实例化会造成任何积极的危害。 (“可实例化”是一个词吗?无论如何。)我们可以争论某人对原始对象实例的任何特定使用是否是一个好主意。但即使你能让我相信我所见过的原始对象实例的每一次使用都是一个坏主意,但这仍然不能证明那里可能没有好的用途。因此,如果它不会造成任何伤害,而且可能会有所帮助,即使我们目前想不出一种真正有帮助的方法,为什么要禁止它呢?
Seems to me there's a simple question of practicality here. Making a class abstract takes away the programmer's ability to do something, namely, to instantiate it. There is nothing you can do with an abstract class that you cannot do with a concrete class. (Well, you can declare abstract functions in it, but in this case we have no need to have abstract functions.) So by making it concrete, you make it more flexible.
Of course if there was some active harm that was done by making it concrete, that "flexibility" would be a drawback. But I can't think of any active harm done by making Object instantiable. (Is "instantiable" a word? Whatever.) We could debate whether any given use that someone has made of a raw Object instance is a good idea. But even if you could convince me that every use that I have ever seen of a raw Object instance was a bad idea, that still wouldn't prove that there might not be good uses out there. So if it doesn't hurt anything, and it might help, even if we can't think of a way that it would actually help at the moment, why prohibit it?
我认为到目前为止所有的答案都忘记了 Java 1.0 是什么样的。在Java 1.0中,你不能创建一个匿名类,所以如果你只是想要一个用于某种目的的对象(同步或空占位符),你就必须为此目的声明一个类,然后一大堆代码就会有这些额外的类就是为了这个目的。更直接地只允许直接实例化对象。
当然,如果您今天正在设计 Java,您可能会说每个人都应该这样做:
但这在 1.0 中不是一个选项。
I think all of the answers so far forget what it was like with Java 1.0. In Java 1.0, you could not make an anonymous class, so if you just wanted an object for some purpose (synchronization or a null placeholder) you would have to go declare a class for that purpose, and then a whole bunch of code would have these extra classes for this purpose. Much more straight forward to just allow direct instantiation of Object.
Sure, if you were designing Java today you might say that everyone should do:
But that was not an option in 1.0.
我怀疑设计者不知道人们将来会以何种方式使用对象,因此不想通过强制程序员在不必要的地方创建额外的类来限制程序员,例如互斥体、键之类的东西ETC。
I suspect the designers did not know in which way people may use an Object may be used in the future, and therefore didn't want to limit programmers by enforcing them to create an additional class where not necessary, eg for things like mutexes, keys etc.
这也意味着它可以在数组中实例化。在 1.5 之前的日子里,这将允许您拥有通用的数据结构。在某些平台上这可能仍然成立(我正在考虑 J2ME,但我不确定)
It also means that it can be instantiated in an array. In the pre-1.5 days, this would allow you to have generic data structures. This could still be true on some platforms (I'm thinking J2ME, but I'm not sure)
对象需要具体的原因。
反思
请参阅 Object.getClass()
通用使用(Java 5 之前)
比较/输出
请参阅 Object.toString()、Object.equals()、Object.hashCode() 等。
同步
请参阅 Object.wait()、Object.notify() 等
尽管有几个区域已被替换/弃用,但仍然需要一个具体的父类来为每个 Java 类提供这些功能。
Object 类用于反射,因此代码可以调用不确定类型实例的方法,即“Object.class.getDeclaredMethods()”。如果对象是抽象的,那么想要参与的代码必须实现所有抽象方法,然后客户端代码才能使用它们的反射。
根据 Sun 的说法,抽象类是声明为抽象的类——它可能包含也可能不包含抽象方法。抽象类无法实例化,但可以子类化。 这也意味着您无法调用抽象类的方法或访问抽象类的公共字段。
抽象根类的示例:
AbstractBaseClass 的子类:
这不会编译,因为在构造函数中引用“this”是无效的,除非它调用同一类中的另一个构造函数。如果我将其更改为:,我就可以编译它:
但这仅有效,因为 ReflectedClass 有一个父级(“对象”),它是 1)具体的,2)有一个字段来存储其子级的类型。
一个更典型的反射示例是在非静态成员函数中:
除非将字段“clazz”更改为静态,否则该函数将会失败。对于对象的类字段,这是行不通的,因为它应该是特定于实例的。 Object 拥有静态类字段是没有意义的。
现在,我确实尝试了以下更改,它有效,但有点误导。它仍然需要扩展基类才能工作。
Java5 之前的泛型(如数组)是不可能的。
需要构造实例来充当占位符,直到收到实际对象为止。
Reasons why Object needs to be concrete.
reflection
see Object.getClass()
generic use (pre Java 5)
comparison/output
see Object.toString(), Object.equals(), Object.hashCode(), etc.
syncronization
see Object.wait(), Object.notify(), etc.
Even though a couple of areas have been replaced/deprecated, there was still a need for a concrete parent class to provide these features to every Java class.
The Object class is used in reflection so code can call methods on instances of indeterminate type, i.e. 'Object.class.getDeclaredMethods()'. If Object were to be Abstract then code that wanted to participate would have to implement all abstract methods before client code could use reflection on them.
According to Sun, An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed. This also means you can't call methods or access public fields of an abstract class.
Example of an abstract root class:
A child of our AbstractBaseClass:
This will not compile because it's invalid to reference 'this' in a constructor unless its to call another constructor in the same class. I can get it to compile if I change it to:
but that only works because ReflectedClass has a parent ("Object") which is 1) concrete and 2) has a field to store the type for its children.
A example more typical of reflection would be in a non-static member function:
This fails unless you change the field 'clazz' to be static. For the class field of Object this wouldn't work because it is supposed to be instance specific. It would make no sense for Object to have a static class field.
Now, I did try the following change and it works but is a bit misleading. It still requires the base class to be extended to work.
Pre-Java5 generics (like with arrays) would have been impossible
Instances need to be constructed to serve as placeholders until the actual objects are received.
我怀疑简短的答案是集合类在 Java 泛型出现之前丢失了类型信息。如果集合不是通用的,那么它必须返回一个具体的对象(并在运行时向下转换为之前的任何类型)。
由于将具体类转变为抽象类会破坏二进制兼容性(如上线程所述),因此保留了具体的 Object 类。我想指出的是,它的创建绝不是为了同步的唯一目的;它是为了实现同步而创建的。虚拟类也同样有效。
设计缺陷是从一开始就没有包含泛型。许多设计批评都是针对该决定及其后果。 [哦,还有数组子类型规则。]
I suspect the short answer is that the collection classes lost type information in the days before Java generics. If a collection is not generic, then it must return a concrete Object (and be downcast at runtime to whatever type it was previously).
Since making a concrete class into an abstract class would break binary compatibility (as noted upthread), the concrete Object class was kept. I would like to point out that in no case was it created for the sole purpose of sychronization; dummy classes work just as well.
The design flaw is not including generics from the beginning. A lot of design criticism is aimed at that decision and its consequences. [oh, and the array subtyping rule.]
它不是抽象的,因为每当我们创建一个新类时,它都会扩展 Object 类,那么如果它是抽象的,您需要实现 Object 类的所有方法,这是开销...该类中已经实现了方法...
Its not abstract because whenever we create a new class it extends Object class then if it was abstract you need to implement all the methods of Object class which is overhead... There are already methods implemented in that class...