为什么我们需要将Object类作为所有类的基类?

时间:2010-06-24 09:30:14

标签: c# java oop

无论是在C#或Java中,还是在oops概念之后的任何其他语言中,默认情况下概念都将“Object”作为超类。为什么我们需要将Object作为我们创建的所有类的基类?

当在C#或Java等语言中无法进行多重继承时,如果已经从Object类派生,我们如何从另一个类派生我们的类。这个问题可能看起来很傻,但想知道一些专家的意见。

9 个答案:

答案 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环境中,将有三个可用的根类(ObjectNSObjectNSProxy),您可以通过不声明超类来编写自己的根类。事实上,Object已被弃用,仅出于遗留原因而存在,但在此讨论中包含它是有用的。这种语言是鸭子类型,所以你可以将变量的类型声明为“任何旧对象”(写成id),然后它甚至不管它有什么根类。

好的,所以我们已经拥有了所有这些基类。事实上,即使编译器和运行时库能够到达任何地方,他们也需要一些共同的行为:根类必须都有一个名为isa的指针ivar,它引用一个类定义结构。没有该指针,编译器不知道如何创建对象结构,并且运行时库将不知道如何找出对象是什么类,它的实例变量是什么,它响应什么消息等等。

所以即使Objective-C声称有多个根类,实际上还有一些所有对象必须实现的行为。所以除了名称之外,其他所有的超级类都是如此,尽管它的API比java.lang.Object少。

N.B。实际上,NSObjectNSProxy都通过协议(如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)

它就像一个模板,用于从中派生出来的所有对象,因此默认情况下会提供每个对象所需的一些常用功能。例如克隆,哈希码和对象锁定等。