对象和实例的区别

94

我知道这种问题以前已经被问过了,但我仍然觉得答案对我(以及一些/大多数初学者)来说太模糊了。

我一直在尝试自学编程的更广泛概念,而不仅仅是过程性和基本面向对象编程。我理解面向对象编程的具体概念(你创建一个类,其中包含数据(成员)和函数(方法),然后在运行时实例化该类以实际执行操作,那种东西)。

我认为我已经掌握了类是什么(有点像在编译时创建实例的设计蓝图)。但如果是这样,那么对象又是什么呢?我也知道,在基于原型的语言中,这可能会让事情变得更加混乱,但也许这就是为什么在我的思维中需要清晰区分对象和实例的原因。

除此之外,我对“对象”和“实例”的概念感到困惑。我读过许多资源(包括SO上的答案),它们说它们大体相同,区别在于语义。其他人则说两者之间存在真正的概念差异。
SO的专家能够帮助初学者达到“恍然大悟”的境界,进入面向对象编程的世界吗?
注:这不是作业,我不是学生——然而,我认为这会帮助那些正在寻找作业帮助的人们。

1
我想知道你是否想添加一些额外的问题,比如“所有实例都是对象吗?”和“所有对象都是实例吗?”如果两个问题的答案都是“是”,那么我们可以确认它们是相同的。 - WesternGun
一旦您使用new实例化一个类,那个被实例化的东西就成为了一个对象。对象是可以遵循面向对象编程的封装、多态、抽象原则的,并且是程序与之交互以消耗类中定义的实例成员的真正事物。对象包含实例成员(非静态成员)。因此,类的实例是一个对象。当您提到它的起源时,使用“实例”这个词更清晰,如果您说“类的对象”相比之下就不太清晰了。 - Praveen Tiwari
15个回答

141

房屋设计蓝图就像一个类的描述。所有按照该蓝图建造的房屋都是该类的对象。一座具体的房子是该类的实例。


6
还有我家乡的一条街,在"住宅开发"的概念出现之前,有8栋完全一样的砖房子,因此在当地颇受关注。所以我能很好地想象出这个情景。"类"是建筑师设计的,而建造完成的房子是"对象",因为它们都是完全相同的。每栋房子都是一个"实例",因为它们可以(并且一直会)被以不同的方式对待,例如现在其中一栋已经加装了侧墙板:o(。 - TCCV
17
静态方法就像所有房屋共享的实用程序。 - WOPR
2
但是从蓝图建造的房子不也是一个实例吗? - Hot Licks
1
这意味着类定义所占据的第一个内存是实例。而所有被创建的对象都称为对象。 - Hafiz Shehbaz Ali
6
对象和实例不是完全相同的概念吗? - Praveen Kumar
显示剩余4条评论

44
事实是,面向对象编程通常会通过将开发的哲学思想和计算机的实际机械运作之间产生一种脱节而导致混淆。我会尝试为您对比这两者:
面向对象编程的基本概念就是:类 >> 对象 >> 实例。
类 = 蓝图。 对象是根据“蓝图”构建的实际物品(如房子)。 实例是对象的虚拟副本(但不是真正的副本)。
“实例”的更技术性的解释是它是一个“内存引用”或一个引用变量。这意味着“实例”是内存中的一个变量,它只有一个对象的内存地址。它所寻址的对象是该实例所说的“实例”。如果您有许多对象的实例,则您在内存中只有许多处于不同位置的变量,它们都具有相同的确切内存地址 - 这些地址都是同一个确切对象的地址。您永远无法“更改”实例,尽管在您的代码中看起来像可以。当您“更改”实例时,您实际上是直接更改原始对象。在电子方面,处理器在更改原始对象的数据之前经过一个额外的内存位置(引用变量/实例)。
处理流程是:处理器 >> 实例的内存位置 >> 原始对象的内存位置。
请注意,无论使用哪个实例,最终结果都将是相同的。所有实例将继续在它们的内存位置中维护完全相同的信息 - 对象的内存地址 - 而只有对象会更改。
类和对象之间的关系有点更令人困惑,尽管在哲学上它是最容易理解的(蓝图>>房子)。如果对象是在某个地方的实际数据,则“类”是什么?事实证明,机械上说,对象就是类的精确副本。因此,类只是内存中的另一个变量,它在技术上保存与对象完全相同的信息。请注意关系之间的差异:
对象是类的副本。 实例是一个变量,它持有对象的内存地址。
您还可以拥有多个相同类的对象,然后每个对象的多个实例。在这些情况下,每个对象的实例集在值上是等效的,但对象之间的实例不是。例如:
假设有一个类A。 从类A派生出Object1、Object2和Object3。
// Object1与Object2和Object3具有完全相同的值,但位于不同的内存位置。
从Object1 >> 派生obj1_Instance1,obj1_Instace2,obj1_Instance3。
// 所有这些实例的值也相等,位于不同的内存位置。它们的值为Object1.MemoryAddress。
等等。
当你开始引入类型时,情况会变得更加混乱。以下是使用C#类型的示例:
// 假设存在Person类 Person john = new Person();
实际上,如果您将其分解为两个部分,那么这段代码就更容易分析:
Person john;
john = new Person();

在技术语言中,第一行“声明一个类型为Person的变量”。但这是什么意思呢?通常的解释是,我现在有一个空变量,只能容纳Person对象。但等一下——它是一个空变量!那个变量的内存位置里什么也没有。事实证明,“类型”在机械上毫无意义。类型最初是作为管理数据的一种方式而发明的,除此之外别无他用。即使你声明基本类型如int、str、chr(未初始化),计算机内部也不会发生任何事情。编程中这种奇怪的句法方面是人们认为类是对象蓝图的思想来源之一。随着委托类型、事件处理程序等类型的出现,面向对象编程变得更加混乱了。我建议不要过多关注它们,只需记住它们都是错误的称呼。直到变量成为对象或设置为对象的内存地址时,变量才会发生变化。

第二行也有点令人困惑,因为它同时完成了两件事:

"new Person()"的右侧首先被评估。它创建了一个Person类的新副本,也就是创建了一个新对象。

左侧的"john ="在此之后进行评估。它将john转换为引用变量,给它赋予刚刚在同一行右侧创建的对象的内存地址。

如果你想成为一个好的开发者,理解一个重要的事情是,没有任何计算机环境是基于哲学理念工作的。甚至可以说计算机并不那么逻辑——它们只是由基本布尔电路(主要是NAND和OR)组合而成的一大堆电线。


36
这个词来自于分类将某物归入的一种类别)。我们都听说过,一个就像蓝图,但这到底是什么意思呢?这意味着包含特定类别的描述(我想用Java举例说明Class、Object和Instance之间的区别,并请求读者在阅读时将其视为故事,如果您不熟悉Java也没关系。)那么,让我们从创建一个HumanBeing类别开始,Java程序如下所示:
class HumanBeing{ 
   /*We will slowly build this category*/ 
}

现在一个 人类 通常具有哪些属性,比如名字年龄身高体重。现在让我们将其限定在这四种属性中,并将其添加到我们的类别中。

class HumanBeing{
    private String Name;
    private int Age;
    private float Height;
    private float Weight; 

   /*We still need to add methods*/

}

现在每个类别都有一个行为,例如类别Dog有吠叫、抓取、滚动等行为...同样地,我们的类别HumanBeing也可以有某些行为,例如当我们问我们的HumanBeing姓名/年龄/体重/身高时,它应该给我们它的姓名/年龄/体重/身高,所以在Java中我们这样做:

class HumanBeing{
    private String Name;
    private int Age;
    private float Height;
    private float Weight;  

    public HumanBeing(String Name,int Age,float Height,float Weight){
       this.Name = Name;
       this.Age  = Age;
       this.Height = Height;
       this.Weight = Weight;
    }

    public String getName(){
      return this.Name;
    }

    public int getAge(){
      return this.age;
    }

    public float getHeight(){
      return this.Height;
    }

    public float getWeight(){
      return this.Weight;
    }
}

现在我们已经给我们的类别HumanBeing添加了行为,因此我们可以询问其姓名、年龄、身高、体重,但你要向谁询问这些细节呢?因为class HumanBeing只是一个类别,它是一个蓝图,例如建筑师在纸上制作建筑物的蓝图,现在我们不能在蓝图中生活(它是建筑物的描述),只有建成后才能住在建筑物里。

因此,在这里我们需要从上面描述的类别中制作一个人类,那么我们该如何在Java中实现呢?

class Birth{
  public static void main(String [] args){
    HumanBeing firstHuman = new HumanBeing("Adam",25,6.2,90);    
  }
}

在上面的例子中,我们创建了一个名为姓名、年龄、身高、体重的人类,那么在上面的代码中到底发生了什么呢? 我们实例化了我们的类别HumanBeing,也就是创建了我们类的一个对象。

注意:Object和Instance不是同义词有时候看起来Object和Instance好像是同义词,但它们并不是。我会给出两种情况

情况1:对象和实例似乎是同义词
让我详细解释一下,当我们说HumanBeing firstHuman = new HumanBeing("Adam",25,6.2,90);时,我们在堆内存中创建了我们类别的一个对象,并分配了一些地址给它,而firstHuman持有该地址的引用,现在这个对象是HumanBeing的一个对象,也是HumanBeing的一个实例。 在这里,似乎对象和实例是同义词,我会重复一遍,它们不是同义词

让我们继续我们的故事,我们创建了我们的第一个人类,现在我们可以问他的名字、年龄、身高、体重,这是在Java中实现方法。

class Birth{
  public static void main(String [] args){
    HumanBeing firstHuman = new HumanBeing("Adam",25,6.2,90);
    System.out.println(firstHuman.getName());
    System.out.println(firstHuman.getAge());
    ...
    ...  
  }
}

所以我们首先有了人类,然后逐步赋予他一些资质,让他成为医生,因此我们需要一个名为Doctor的类别,并给我们的医生一些行为,因此在Java中我们可以这样做:

class Doctor extends HumanBeing{
   public Doctor(String Name,int Age,float Height,float Weight){
      super(Name,Age,Height,Weight);
   }
   public void doOperation(){
    /* Do some Operation*/ 
   }

   public void doConsultation(){
    /* Do so Consultation*/
   }
}  

在这里,我们使用了继承的概念,它为代码带来了一些可重用性,每个医生首先都是一个人类,所以医生将从人类那里继承姓名、年龄、体重、身高,而不是重新编写代码。请注意,我们只是描述了医生,还没有创建一个医生,所以让我们在Birth类中创建一个医生。

class Birth{
  public static void main(String [] args){
    Doctor firstDoctor = new Doctor("Strange",40,6,80);
    .......
    .......
    /*Assume some method calls , use of behaviour*/
    .......
    .......    
  }
}

情况2:对象和实例不是同义词
在上面的代码中,我们可以看到我们正在实例化我们的 Doctor 类别并将其带到生活中,即我们只是创建Doctor类别的对象,因为我们已经知道对象是在堆内存上创建的,而 firstDoctor 保存了一个对堆上该对象的引用;

这个特定的对象 firstDoctor 如下所示(请注意,firstDoctor 保存了一个对对象的引用,它不是对象本身)

  1. firstDoctorDoctor 类的一个对象Doctor 类的一个实例
  2. firstDoctor 不是 HumanBeing 类的一个对象,但是是 HumanBeing 类的一个实例

因此,一个特定的对象可以是某个类的实例,但不一定是该给定类的对象

结论:

如果一个对象满足该特定类别的所有特点,则称该对象是该特定类别的一个实例。

现实世界的例子如下,我们首先作为人类出生,所以把我们想象成人类的对象,现在当我们长大并承担责任、学习新技能和扮演不同的角色时,例如儿子、兄弟、女儿、父亲、母亲,我们到底是什么呢?我们可以说我们是人类的对象,但是是兄弟、女儿等的实例。

希望这有所帮助

谢谢


5
为什么这个回答只有3个赞? - Pratik Ambani
1
感谢您的精彩解释 - 这是您的常识还是有实际的理论参考来官方确认这个解释? - Ulysses
@hard_working_ant 谢谢,我并不知道有任何实际的文档,我的老师让我明白的,我所做的只是将其放入一个简单的例子中。 - Pushkarraj Pujari

14

这里输入图片描述

对象是内存中的东西,而实例是对它们的引用。在上图中:

  • std(instance) -> 学生对象(右侧)
  • std1(instance) -> 学生对象(左侧)
  • std2(instance) -> 学生对象(左侧)
  • std3(instance) -> 没有对象(null)

4
太好了。我真的很喜欢它能够降到低层次的事实。我对于这比类比更好的喜好反复思考。我认为知道两者的结合才是我真正所需要的。点赞,但不确定是否可以把答案给你,因为已经给Joe了。谢谢你,这解决了很多问题。 - TCCV
1
那么,实例是指向对象的指针吗?(实例==具有内存地址的变量?) - Stano
8
Truong,你的回答是错误和令人困惑的。实际上,实例是从基类对象派生出来的对象。实例==对象。例如,这个术语在这个这个答案中解释得很好。 - Stano
@jww:该图片链接为http://math.hws.edu/javanotes/c5/objectsInHeap.png,但现在已经404。可能在发布时是可见的。 - Matt Burland

7
一个对象是一个类的实例(对于基于类的语言)。 我认为这是我能想到的最简单的解释。

2
我同意你的解释基本上是正确的,但是网上有很多条目区分了这两者。我不知道这种问题是否需要考虑语言因素(哇,一个元问题,这个问题就像一个类,如果没有使用语言实例化它,那么它就无法使用,哈哈)。 - TCCV

6

类定义了一个对象。在许多编程语言中,可以更进一步地说接口定义了对象之间的共同属性和方法。

对象是可以代表现实世界中某些事物的东西。当您想要让对象实际上代表现实世界中的某些东西时,必须对该对象进行实例化。实例化意味着必须通过构造函数定义此特定对象的特征(属性)。

一旦定义了这些特征,就会有一个对象实例。

希望这能够解决问题。


我认为这基本上是在说Joe所说的话。如果我错了,请纠正我。 - TCCV
4
乔(Joe)说所有按照蓝图建造的房屋都是对象,这是正确的。他还说特定的房屋是实例,也是正确的。但是,所有的房屋都是实例,并且特定的房屋也是一个对象。他在不存在差别的地方进行了区分。在代码中,我们需要在构建时区分对象和实例。当它被建造出来时,我们说它已经被实例化。一个常见的问题可能是:你记得实例化对象了吗?即,如果在声明对象后忘记调用构造函数。 - Derek Litz
1
啊,这是一个很好的区分。换句话说,实例是已经构建(即已调用构造函数)的对象。 - TCCV

3

什么是对象?

对象是类的一个实例。可以通过身边的真实世界例子更好地理解对象。你的桌子、笔记本电脑、汽车都是好的真实世界对象示例。

真实世界的对象具有两个特征:它们都有状态和行为。人类也是一个很好的对象示例,我们人类有状态/属性 - 名字、身高、体重和行为 - 走路、跑步、说话、睡觉、编码:P。

什么是类?

类是描述对象细节的蓝图或模板。这些细节包括:

名称 属性/状态 操作/方法

class Car 
{
    int speed = 0;
    int gear = 1;

    void changeGear(int newGear)
    {
        gear = newGear;
    }

    void speedUp(int increment) 
    {
        speed = speed + increment;
    }

    void applyBrakes(int decrement) 
    {
        speed = speed - decrement;
    }
}

考虑上面的例子,字段 speedgear 将表示对象的状态,方法 changeGearspeedUpapplyBrakes 定义了 Car 对象与外界的行为。
参考资料:

3
"

一个类描述了一组被称为其实例的对象。" - 零克斯学习研究小组,“Smalltalk-80系统”,Byte杂志第06卷第08期,1981年。

"

1

我认为需要指出的是,通常有两个东西。蓝图和副本。人们倾向于给它们不同的名称; 类、对象、实例只是人们用来称呼它们的一些名称。重要的是有蓝图和它的副本 - 不管它们的名称如何。如果你已经理解了这两个概念,就避免其他让你感到困惑的事情。


0

在本主题中扩展之前给出的一个例子...

考虑这样一个场景 - 在一个社区需要建造5栋住宅。所有5栋住宅共享相同的建筑结构。 建筑结构是一个。 房屋是一个对象。 每个有人居住的房屋都是一个实例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接