在Java中,对象变量是否包含对象的地址?

5

我和我的老师交谈时,她提到一个对象变量(指的是一个对象实例)并不包含对象本身,而是其在内存中的地址。

我听说在Java中,对象实例确实包含对内存中对象的引用。我错了吗?引用和包含内存地址是相同的东西,还是其他什么?

7个回答

13

一个对象变量并不等同于一个对象实例。你需要明确区分变量、它们的值和对象之间的差别,这非常重要。

例如:

String x = "hello";
< p >变量< em >x < /em >。它就像一张纸,上面可以写上< em >值< /em >。< /p > < p >变量的< em >值< /em >是一个引用——一些数据,VM可以使用它来获取字符串对象本身。它不一定是一个地址,只是“获取对象数据的一种方式”。(想了解更多信息,请阅读Eric Lippert的博客文章“引用并非地址”——这是针对C#而非Java,但原理相同)。< /p > < p >< em >对象本身是一个独立的实体。< /p > < p >举个现实中的例子,想象我有一张写着我的家庭地址的纸。这里显然有三件事:< /p >
  • 这张纸(就像一个变量)。这张纸本身不是我的家庭地址,也不是一所房子。它只是可以存储值的东西。
  • 我的家庭地址不是一张纸,也不是一座房子。它只是一个让人们到达我的房子的值。
  • 我的房子既不是一张纸,也不是一个地址。它是一个对象。< /li>

当你考虑参数传递和变量赋值等问题时,这变得很重要。例如:< /p>

House x = new House("Jon");
House y = x;

这里有两个变量,xy,就像两张纸一样。我们建造了一座房子,并在 x 上写下了到达它的指示。然后我们将写在 x 上的值复制y 上。请注意,它们仍然是完全独立的纸张,但它们目前具有相同的值。只有一个对象 - 我们只建造了一座房子 - 但现在两张纸上都写有同样的指示。

如果一个人按照纸张 x 上的指示把门漆成红色,那么另一个人按照纸张 y 上的指示他们会找到一座带有红色前门的房子。

另一方面,如果一个人涂掉了纸张 x 上的指示,那并不会对纸张 y 上的指示产生影响。


5

好的,不完全是内存地址,但在JVM中可以将其翻译成类似的东西。

问题在于Foo foo = new Foo()只是对Foo的引用,而不是整个Foo结构。


1
我认为“是”可能是一个可以接受的答案,尽管它是一个虚拟内存地址。 - Bohemian
除了它不是这样的 - 好吧,也许是,但当使用压缩的Oops在Hotspot x64上时,它并不必须是这样的,实际上也不是。因此,在理论上,这种差异很重要,尽管我同意我们正在超出OP的理解范围。 - Voo

1

引用是指对象在内存中的地址。这个“内存”实际上更像是一块空间,用于创建与执行无关的东西(调用帧等实际上用于执行)。


0

是的,有点类似。当你使用new运算符分配一个对象时,它被分配在堆上,并返回对该位置的引用。当你声明一个变量如:Object foo时,foo变量并没有被分配在堆上。变量不是对象,而是对象的引用。它们被创建在栈上作为局部变量或者在对象中作为实例变量。foo可以引用堆上的某个东西。它非常像C语言中的指针,但主要区别在于它不仅仅是一个内存地址(原因有点复杂,但就所有目的而言,你可以把引用看作指针)。Java与C语言最大的区别在于你不能操作指针。你不能确定它的值,也不能对它进行任何数学运算。这些都是为了你自己和程序的安全考虑。你可以通过将其赋值给另一个引用或null来更改foo指向的内容。


变量也不是引用。变量的值可能是引用,但这是另一回事。请注意,堆栈区别大多是实现细节,而聪明的JVM有时能够在堆栈上分配对象,如果它们能够证明它们不会“逃逸”。 - Jon Skeet
我会说Java引用和C++引用非常相似(使用&修饰符声明)。行为和语法几乎相同。 - Sam Goldberg

0

Car c = new Car();

在上面的例子中,c是一个引用变量,它包含由new运算符生成的引用ID,该ID以哈希码形式包含对象的位置,因为出于安全目的。在Java中,引用ID类似于C ++中的指向指针,因为它是一个内存位置,其中包含对象实际存在的内存位置。引用ID始终在堆栈中获得内存,而对象始终在堆中获得内存。


0

请考虑

 A a1 = new A();

这里A是一个类,a1是引用变量,指向堆内存中的某个位置。堆内存中的区域(也称为对象)包含属性和方法(方法用于消息传递,存储在方法表中)。

如果从创建对象的类中调用对象,则不需要使用点符号。否则,我们必须使用点符号。

例如:

 class A
 {
   static int age;
   static int email;

  mehtod1()
  {
   }
  mehtod2()
  {
  }

  ...
 ...
 ...

 A a1 = new A();
 A a2 = new A();
A a3 = a1;
 }

现在a1和a3是同一个,每个a1、a2和a3只有对静态全局属性(而不是每个对象一个)age和email的一个副本进行访问;
现在
 class B
 {

 some attributes;
...
 ...
 ...

 a1.method1();// will pass method 1 to object1

}

在Java中,对对象的调用几乎就像处理数学问题(例如在两个变量之间使用表达式2+4=6)和英语一样。

就像“机器人向左移动5个单位”。

                robot.movesleft(5); // robot is object and movesleft is method or function which tells robot what to do can be anything like eat(banana), sleep(50) blah blah

将“+”替换为“点”

 Objects are purely handled at JVM and Computer doesnot know what objects are(hardware only knows subroutines(sub-functions) and attributes)

如果我哪里错了,请纠正我


-1

实例不持有内存地址,而是持有一些只有JVM能够理解的地址。例如下面的示例中,h1 持有 "com.mmm.examples.Hippo@3d4eac69",其中 "packageName.ClassName@someaddress"

示例:

Hippo h1 = new Hippo();
System.out.println(h1);
System.out.println("h1.size = " + h1.size);// 
com.mmm.examples.Hippo@3d4eac69

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