1.参考变量
在 Java 语言中,有两种变量:原始变量和其他变量。碰巧的是,我们现在要谈谈“其他一切”。
其实说有原始变量和引用变量更正确。那么这些参考变量是什么?
与变量直接存储值的原始类型不同,引用变量存储对对象的引用。即内存某处有一个对象,引用变量只是存储了这个对象在内存中的地址(对象的引用)。
只有基本类型将值直接存储在变量中。所有其他类型只存储一个对象引用。顺便说一下,您已经遇到过两种类型的变量——String
变量和数组变量。
数组和字符串都是存储在内存中某处的对象。String
变量和数组变量仅存储对对象的引用。
int a, int b and double d
是将它们的值存储在自身内部的原始变量。
变量String str
是一个引用,将地址(引用)存储到String
内存中的对象。
将原始值分配给原始类型的变量时,其值被复制(复制)。分配引用变量时,仅复制对象的地址——不复制对象本身 。
2. 什么是参考文献?
参考变量和原始变量之间的根本区别是什么?
原始变量就像一个盒子:您可以在其中存储一些值。参考变量更像是一张上面有电话号码的纸。
汽车 vs 汽车钥匙
想象一下,您决定在朋友生日时送他一辆车。你不会把它包在一个盒子里随身携带:汽车太大了。
将车钥匙放在一个足够大的盒子里会方便得多。当他从盒子里拿出钥匙时,你的朋友就会明白一切。当您只需交出钥匙时,就无需随身携带整辆车。
一个人 vs 她的电话号码
或者这是另一个比较:一个人和她的电话号码。一个电话号码不是那个人,但是一个电话号码可以用来给她打电话,向她询问一些信息,或者提供指示。
类似地,引用用于与对象交互。所有对象都使用引用相互交互。我们不是“交换人”,而是简单地交换电话号码。
为原始变量赋值时,其值被复制(复制)。为引用变量赋值时,只会复制对象的地址(电话号码)——不会复制对象本身。
引用提供了另一个优势:您可以将对象引用传递给某个方法,该方法将能够通过使用对对象的引用、调用对象的方法和访问对象内部的数据来修改(更改)对象。
3.分配引用
分配引用变量时,只分配对象在内存中的地址。对象本身不会出现或消失。
这种方法避免了复制大量内存。如果您需要将一个非常大的对象传递给方法,我们只需传递对象引用即可。引用占用的空间要少得多。
所有引用变量(无论其类型如何)的大小都是相同的 — 4 个字节(类似于 int)。但!如果您的应用程序在 64 位 Java 机器上运行,那么所有引用的大小都是 8 字节(64 位)。
更何况,引用只能相互赋值。您不能更改引用或为引用变量分配任意值:
代码 | 描述 |
---|---|
|
这是允许的 |
|
但这是不允许的 |
|
这是不允许的 |
4.null
参考
如果还没有分配给它,引用变量存储什么?
它存储空引用。null
是一个特殊的 Java 关键字,表示没有引用(空引用)。该null
值可以分配给任何引用变量。
所有引用变量都是,null
除非它们已经分配了某种引用。
例子:
代码 | 描述 |
---|---|
|
该 String name 变量有一个默认值:null 。该 int age 变量有一个默认值:0 。 |
对于原始类型和引用类型,未赋值的局部变量被视为未初始化。
如果一个变量存储了对某个对象的引用,而您想清除该变量的值,则只需为其分配一个空引用即可。
代码 | 描述 |
---|---|
|
s 商店null 。存储对字符串对象存储的s 引用。s null |
5.传递对方法的引用
如果方法的参数是引用类型,则值将以与处理非引用变量时相同的方式传递给该方法。该参数只是简单地分配了另一个变量的值。
例子:
代码 | 描述 |
---|---|
|
用传递的值 ( )填充 fill 传递的数组( )。array value |
fill
调用该方法时,array
参数会被分配一个对数组的引用data
。该value
变量被分配了对字符串对象(“Hello”)的引用。
这是调用方法之前 内存的样子fill
:
这是方法运行时 内存的样子fill
:
和变量引用(存储引用)内存中的同一容器data
。array
该value
变量存储对字符串对象 ( ) 的引用"Hello"
。
数组的单元格也只存储对"Hello"
对象的引用。
事实上,没有对象被复制——只有引用被复制。
6.与C/C++语言的比较
在面试中,有时会问 Java 程序员,Java 中数据是如何传递给方法的?有时问题是数据是按引用传递还是按值传递?
这个问题来自 C++,但在 Java 中意义不大。在 Java 中,参数总是简单地分配参数的值。所以正确的答案是“按价值”。
但是请准备好解释您的立场,因为您可能会立即听到反驳:“原始类型按值传递,而引用类型按引用传递。”
这个问题的由来源于很多Java程序员过去都是C++程序员。在该编程语言中,如何将参数传递给方法的问题非常重要。
在 Java 中,一切都是明确的:基本类型存储值,而引用类型也存储一个值——一个引用。这是一个变量是否被认为是一个值的问题。
在 C++ 中,变量可以存储对对象的引用和对象本身。原始类型也是如此:原始变量可以存储一个值或将变量声明为对int
. 因此,为了避免混淆,C++ 程序员总是将引用的对象称为引用,将对象本身称为值。
在 C++ 中,您很容易遇到这样的情况:一个变量包含一个对象,而另一个变量包含对该对象的引用。因此,变量存储什么的问题——对象本身或只是对它的引用——非常重要。当一个对象被传递给一个方法时,它被复制(如果通过值传递),而不是被复制(如果通过引用传递)。
在 Java 中,这种二元性不存在,所以正确答案是:arguments are passed to Java methods by value。只是当我们谈论引用变量时,这个值是一个引用。