什么是类、引用和对象?

53

我现在已经学习Java编程两年了,但我遇到了一个问题,我无法理解和区分类、引用和对象。

我不确定类或引用是否相同,尽管我对对象有些了解。

有人能够完整地区分一下类、引用和对象吗?

我所知道的是,类更像是对象的模板(就像房屋的蓝图是类,而房子则是对象)。


从这里开始:http://docs.oracle.com/javase/tutorial/java/index.html。 - home
3
如果您有C语言(或其他过程式语言)的经验,您可以将对象看作具有方法的结构体。因此,“类”将是结构声明(带有相关方法),“对象”将是给定的具体结构体(该结构体是一个对象,那个结构体是另一个对象),而“引用”则是指向该结构体的指针。 - helios
12个回答

149

如果你喜欢房屋比喻:

  • 就像房子的蓝图。使用这个蓝图,你可以建造无数个房子。
  • 每一个你建造的房子(或者在面向对象编程的术语中叫做实例化)是一个对象,也被称为一个实例
  • 每一个房子都有一个地址。如果你想告诉别人房子在哪里,你会给他们一张写着地址的卡片。这张卡片就是对象的引用
  • 如果你想去看房子,你要查看写在卡片上的地址。这叫做解除引用

你可以随意复制这个引用,但只有一个房子 -- 你复制的只是写有地址的卡片,而不是房子本身。

在Java中,你不能直接访问对象,只能使用引用。Java不会复制或者分配对象给其他对象。但是你可以复制和赋值引用到变量,使它们指向同一个对象。Java方法总是按值传递,但是这个值可以是一个对象的引用。因此,如果我有:

Foo myFoo = new Foo();     // 1
callBar(myFoo);            // 2
myFoo.doSomething()        // 4

void callBar(Foo foo) {
    foo = new Foo();       // 3
}

接下来我们来看一下发生了什么。

  1. 第1行发生了几件事情。 new Foo() 告诉 JVM 使用 Foo 蓝图来建造一个新房子。JVM 这样做,并返回房子的引用。您然后将此引用复制到 myFoo 中。这基本上就像要求承包商为您建造一座房子。他建造了房子,然后告诉您房子的地址;您会将该地址写下来。
  2. 在第2行,您将这个地址传递给另一个方法,即 callBar。让我们接下来跳转到该方法。
  3. 在这里,我们有一个引用 Foo foo。Java 是传值调用的,因此 callBar 中的 foomyFoo 引用的 副本。将其视为给 callBar 一张带有房子地址的卡片。那么 callBar 会如何使用这张卡呢?它要求建造一个新房子,然后使用您提供的卡片来写入该新房子的地址。请注意,现在的 callBar 无法访问第一个房子(我们在第1行中建造的那个房子),但该房子并不会因为曾经带有其地址的卡片现在带有其他房子的地址而发生变化。
  4. 回到第一个方法,我们取消引用 myFoo 来调用它的一个方法(doSomething())。这就像查看卡片,在上面写有地址的房子中做某些事情。请注意,callBar 方法不会更改带有 myFoo 地址的卡片 -- 记住,我们给了 callBar 我们引用的 副本

整个序列可能类似于:

  1. 要求 JVM 建造一所房子。它这样做,并给我们地址。我们将此地址复制到名为 myFoo 的卡片中。
  2. 我们调用 callBar。在此之前,我们将写在 myfoo 上的地址复制到一张新卡片上,然后将它交给 callBar。它称该卡片为 foo
  3. callBar 要求 JVM 建造另一座房子。它创建了一个新房子,并返回新房子的地址。 callBar 将此地址复制到我们给它的卡片中。
  4. 回到第一个方法,我们查看原始的、未更改的卡片;去到地址在我们卡片上的房子;并在那里做一些事情。

引用和地址有什么区别?感觉你在某种程度上将它们交替使用。从这个答案中可以看出,“指针的引用”用于解除变量的引用。但是什么是引用?一个数字?还是指向指针的指针? - Quazi Irfan
2
@iamcreasy 它们非常相似。地址是JVM中(即在内存中)对象所在的位置。引用是指向此地址的变量。类比就像询问整数和int之间的区别一样 - 整数(或地址)是您想要存储的东西,而int(或引用)是存储它的东西。 - yshavit
1
@BKSpurgeon Callbar没有得到一座房子,而是得到了一张卡片,上面写着一座房子的地址。因此,它并没有在那个地址建造新房子——它建造了一座新房子,然后将那座房子的地址写在了卡片上。这意味着Callbar不能再找到旧房子了——但其他人不受影响。旧房子仍然在那里,任何持有旧房子地址的其他卡片的人仍然可以找到它。 - yshavit
@yshavit,感谢您的澄清。我一直完全跟随您,直到您说了这句话-然后我感到困惑:“通话栏无法再找到旧房子”。同意。“但没有其他人受到影响”?旧房地址卡现在难道不会指向通话栏房子吗?我将通过代码进行检查,并回答您,因为这让我感到困惑。 - BenKoshy
1
@BKSpurgeon,Java方法始终是按值传递(对象引用)。因此,当调用callBar(myFoo)时,只传递了值(引用),并且“foo”的范围仅限于callBar内部。而且foo只是得到了一个新的Foo()。所以foo引用了一个新的对象-我想我是正确的。 - Exigente05
显示剩余8条评论

13

当你编程时,你会创建一个

实例(发生、拷贝)

一个

对象

来自于一个特定的

并保留对它的

引用

以便您可以调用其方法。

此外,一些OOP基础知识:, 对象, 实例, 和 引用


当你“保留”一个引用时,这意味着什么?它是像该对象的实现一样吗?还是对象本身就是实现? - user962206
2
@user962206,引用不过是指向内存中对象位置的“指针”。你可以说你在类文件中编写了“实现”,但我不确定这是否是你的意思。 - Marcelo
谢谢,最后一个问题。instance和Objects是相同的吗? - user962206
@user962206 不对:你总是有一个对象的实例(或者一个出现,或者一份拷贝)。请注意Java有一个叫做Object的类,它是所有其他类的层次结构中的父类。 - Marcelo
2
@Marcelo 稍微吹毛求疵一下:这个引用并不是 Car 对象的地址,它只是可以存储地址副本的地方。如果你修改了引用,那么并不会改变 Car 的地址——这只是意味着你现在指向了另一个对象(或者是 null,也就是没有地址)。 - yshavit
显示剩余3条评论

9
在布鲁斯·埃克尔的《Java编程思想》一书中,他完美地描述了以下内容:
“你可以想象一台电视(对象)和一架遥控器(引用)。只要你握住这个引用,你就可以连接到电视,但当有人说“换频道”或“调低音量”时,你所操作的是引用,引用又会修改对象。如果你想在房间里走动而仍然控制电视,你带着遥控器/引用走,而不是带着电视。
此外,遥控器/引用可以独立存在,没有电视也可以。也就是说,仅仅因为你有一个引用并不意味着一定有一个与之相连的对象。因此,如果你想拥有一个单词或句子,你需要创建一个字符串引用:”
String s;

但是在这里,你仅仅创建了一个引用,而不是一个对象。如果此时决定向 s 发送消息,将会出现错误,因为它实际上没有绑定到任何内容(没有电视)。因此更安全的做法是,在创建引用时总是进行初始化:

String s = "asdf";

然而,这里使用了一种特殊的Java功能:可以用引号括起来的文本初始化字符串。通常,您必须为对象使用更一般类型的初始化。

当您创建引用时,您希望将其连接到一个新对象。通常情况下,您需要使用new运算符。关键字new表示:“给我一个新的这个对象。”因此,在前面的示例中,您可以这样说:

String s = new String("asdf");

这不仅意味着“创建一个新的字符串”,而且通过提供初始字符字符串来提供有关如何创建字符串的信息。 当然,除了字符串之外,Java还配备了大量现成的类型。更重要的是,您可以创建自己的类型。实际上,在Java编程中创建新类型是基本活动。


4

假设你在那里写了两行代码:

Engine app1 = new Engine(); //LINE 1

Engine app2  = app1; //LINE 2

在第一行中,Engine是一个“类”,它基本上是一个蓝图。
new Engine()是在堆上创建的“实例”。
您在代码中使用app1和app2来引用该“实例”。
因此,app1和app2是“引用”。

1
如果你说实例,你是指对象吗? - user962206
因此,app2不包含在第1行创建的引擎的副本,它保存指向引擎的引用的副本。 - Jeffrey
当引擎的引用返回null或不指向任何内容时,也会抛出空指针异常。 - Jeffrey

3
当你创建一个对象时,在幕后发生的事情是为该对象保留了一块内存空间。这个内存位置可以在内存中的任何地方,由操作系统和编译器决定,你无法控制或知道它最终的位置。
那么问题来了,如果你不知道对象在内存中的位置,怎么使用它?如果你不知道值存储在哪里,怎么读取值?这就是引用的作用。引用是一种与对象保持联系的方式,它相当于气球上系着的一根小绳子。
你使用引用来表明“我现在想要处理这个对象!”,或者“我想从这个对象中读取一个值!”。

2

类: 结构或蓝图

对象: 物理表现

引用: 对象地址


2

========= 类和对象 ===========

类 => 例如:人(更像是想象)

对象 => 例如:约翰,迈克(真实的人)

=========== 引用 ============

例如:

Television tv1; - (电视是一个类,tv1是没有电视的遥控器)

Television tv2 = new Television(); - (现在tv2遥控器有了一台电视)

tv1 = tv2; - (现在tv1和tv2可以控制同一台电视)

Television tv3 = new Television(); - (tv3是一个新的遥控器,带有新的电视)


1

ObjectClass 定义的运行时表示,而您使用对象的名称称为 reference(因为它引用了内存中实际对象的位置)

例子:

MyClass ref = new MyClass();

这里,MyClass 是(包含)的定义。

new MyClass() 创建了该类的一个对象(仅在执行期间完成,因此是运行时表示)

ref 是您用于处理类对象的名称,是引用


1

类(Class):用于将现实生活中的实体定义到编程环境中。

任何具有至少一个属性和相应行为的现实生活实体都可以被视为一个类。让我们以汽车为例,它具有一个名为“加速器”(accelerator)的属性,帮助汽车移动并控制其速度。相应的行为是“加速”(acceleration),它与施加给加速器的推力成正比。

class Car {
    private String tier;
    private String tierFriction;
    private double weight;
    private double gasFedToEngine;
}

上述类显示了汽车的一些属性,其加速度取决于这些属性。行为(类中的方法)始终取决于属性(类的全局属性)。现在,如果您想要更多详细信息,可以将Tier定义为另一个实体,然后定义将如下所示。
class Tier {
    private String tierMaterial;
    private String tierFriction;
    private double weight;
    private double tierDiameter;
}

class Car {
    private Tier tier;  // getting all properties of Tier here itself
    private double weight;
    private double gasFedToEngine;
}

对象:用于定义实体的各种类型,并对它们进行单独的数据操作。

现在我们已经为程序定义了一个实体,比如说我们拥有一个二手车展厅,里面有不同公司的汽车。因此每辆汽车都成为我们实体的一个对象。对象可以是奥迪、日产、法拉利等。所以在开业后,我们可以像这样向展厅添加汽车:

static List<Car> showroomCars = new ArrayList<Car>();
public boolean addCarToShowroom() {
    Car carNissan = new Car();  // always creates a new objects and allocates some memory in heap
    carNissan.setName("Nissan");
    carNissan.setColor(RED);
    carNissan.setWeight(300);
    showroomCars.add(carNissan);

    Car carAudi = new Car();
    carAudi.setName("Audi");
    carAudi.setColor(BLACK);
    carAudi.setWeight(270);
    showroomCars.add(carAudi);
}

现在Showroom中添加了两辆新车,一辆是日产汽车,另一辆是奥迪汽车,每辆车都有自己特定的属性值。
Class只是给出定义,操作是在Object上完成的,要对任何Class进行操作,必须创建对象。每次将对象创建到类中时,其所有非静态(实例)变量将带有其各自的默认值加载到内存中。
引用:用于寻址对象。当我们说“Car carAudi = new Car();”时,我们为Car定义了一个新对象,并分配了一个内存位置。引用变量carAudi保存该对象的内存地址。用户永远不会直接访问对象,也不会访问其内存位置。这就是引用变量的重要性所在,它存储内存位置的十六进制格式。如果我们想要对对象进行修改,则需要借助引用而不是直接进行。
一个对象可以有任意数量的引用,但引用一次只能指向一个对象。
class Car {
    void test() {
        Car car1 = new Car();  // (1)
        Car car2 = new Car();  // (2)
        car2 = car1;
        /** 
         Says that car2 should point to where car1 points, so now both points to first object of Car
         But for this car2 has to loose its current object-(2), making it an Abandoned object (An object with no active reference from the stack).
        **/
    }
}

1

类是一个模板,你说得对。它是关于数据结构的一些知识。对象是内存中的结构实例。引用是该实例的内存地址。

如果你所说的对象是指Java标识符,那么Object是所有复杂Java类的基本类。


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