无论是在C#或Java中,还是在oops概念之后的任何其他语言中,默认情况下概念都将“Object”作为超类。为什么我们需要将Object作为我们创建的所有类的基类?
当在C#或Java等语言中无法进行多重继承时,如果已经从Object类派生,我们如何从另一个类派生我们的类。这个问题可能看起来很傻,但想知道一些专家的意见。
答案 0 :(得分:14)
具有单根类型的层次结构可以以各种方式方便。特别是在仿制药出现之前,这是像ArrayList
这样的东西才能发挥作用的唯一方式。有了泛型,它的优势明显减少 - 虽然它在某些情况下仍然有用,但我怀疑。编辑:作为一个例子,LINQ to XML的构造模型在通过object
指定方面非常“松散”......但它的效果非常好。
至于派生自不同的类 - 你从一个类直接派生 ,但这又会从另一个派生间接,依此类推到Object。 / p>
请注意,“所有对象都有共同点”的东西,例如哈希码,等式和监视器,都算作另一个设计决策,我会质疑它的智慧。如果没有单一的根系层次结构,这些设计决策可能不会以相同的方式进行;)
答案 1 :(得分:9)
每个类都继承了编译器确保的对象这一事实 这意味着你写的:
class A {}
它将编译如下:
class A : Object{}
但如果你说:
class B : A {}
Object
将位于B
的层次结构中,但不会直接存在 - 因此仍然没有多重继承。
答案 2 :(得分:3)
简而言之
1)Object类定义了所有对象必须具有的基本状态和行为,例如将自己与另一个对象进行比较,转换为字符串,等待条件变量,通知其他对象的能力。条件变量已更改,并返回对象的类。
2)你可以有B扩展C和A扩展B. A是B的子类,B是C的子类。当然,A也是C的子类。
答案 3 :(得分:2)
嗯,Object
的多重继承不适用 - 您可以将其视为:
“如果某个类型没有基本类型,则隐式注入Object
”。
因此,应用规则ad-nauseam,所有类型只从对象继承一次 - 因为在层次结构的底部必须是没有基础的类型;因此,它将隐含地继承自Object
。
至于为什么这些语言/框架将此作为一项功能,我有几个原因:
1)“面向对象”这个名称的线索。一切都是一个对象,因此一切都应该有'对象'(或等价物),否则设计原则就会从一开始就被打破。
2)允许框架为所有类型应该/可能需要支持的常见操作提供挂钩。如哈希码生成,调试字符串输出等等。
3)这意味着你可以避免使用可以破坏东西的令人讨厌的类型转换 - 比如(((int *)(void*))value)
- 因为你有一个很好的友好超类型
可能载入的次数超过了这个 - 并且在我写这篇文章时已经发布了6个新的答案;所以我会把它留在那里,并希望比我更好的人能够更详细地解释,或许更好:)
答案 4 :(得分:1)
关于问题的第一部分,它是类如何接收公共属性和方法。这也是我们如何为可以接受任何对象的函数提供强类型参数。
关于你的第二个问题,你只需从另一个班级派生你的班级;然后它将成为该类的后代,而后者又是Object的后代。没有冲突。
答案 5 :(得分:1)
你有Object基类,因为Object类有方法(比如,在.NET中,GetHashCode()
,它包含每个对象应具有的通用功能。)
多重继承确实不可能,但是可以从B类派生A类,因为A可能不是直接从Object派生,而是B,所以所有类最终派生自Object,如果你在类的继承层次结构中走得足够远。
答案 6 :(得分:1)
为了比较,我们来看一下不强制执行单个根类的语言 - Objective-C。在大多数Objective-C环境中,将有三个可用的根类(Object
,NSObject
和NSProxy
),您可以通过不声明超类来编写自己的根类。事实上,Object
已被弃用,仅出于遗留原因而存在,但在此讨论中包含它是有用的。这种语言是鸭子类型,所以你可以将变量的类型声明为“任何旧对象”(写成id
),然后它甚至不管它有什么根类。
好的,所以我们已经拥有了所有这些基类。事实上,即使编译器和运行时库能够到达任何地方,他们也需要一些共同的行为:根类必须都有一个名为isa
的指针ivar,它引用一个类定义结构。没有该指针,编译器不知道如何创建对象结构,并且运行时库将不知道如何找出对象是什么类,它的实例变量是什么,它响应什么消息等等。
所以即使Objective-C声称有多个根类,实际上还有一些所有对象必须实现的行为。所以除了名称之外,其他所有的超级类都是如此,尽管它的API比java.lang.Object
少。
N.B。实际上,NSObject
和NSProxy
都通过协议(如Java接口)提供类似于java.lang.Object
的丰富API。声称处理id
类型的大多数API(请记住,这是“任何旧对象”类型)实际上会假设它响应协议中的消息。当你真正需要使用一个对象时,而不是仅仅使用编译器创建它时,将所有这些常见行为(如相等,散列,字符串描述等)折叠成有用的结果是有用的。根类。
答案 7 :(得分:1)
多重继承是一个完全不同的球赛。
多重继承的一个例子: -
class Root
{
public abstract void Test();
}
class leftChild : Root
{
public override void Test()
{
}
}
class rightChild : Root
{
public override void Test()
{
}
}
class leafChild : rightChild, leftChild
{
}
这里的问题是leafChild继承了rightChild和leftChild的测试。所以一个冲突的方法的情况。这被称为钻石问题。
但是当你将对象用作超类时,层次结构如下: -
class Object
{
public abstract void hashcode();
//other methods
}
class leftChild : Object
{
public override void hashcode()
{
}
}
class rightChild : Object
{
public override void hashcode()
{
}
}
所以这里我们从Object派生出两个类,但这就是它的结束。
答案 8 :(得分:1)
它就像一个模板,用于从中派生出来的所有对象,因此默认情况下会提供每个对象所需的一些常用功能。例如克隆,哈希码和对象锁定等。