1.参考变量

在 Java 语言中,有两种变量:原始变量和其他变量。碰巧的是,我们现在要谈谈“其他一切”。

其实说有原始变量引用变量更正确。那么这些参考变量是什么?

与变量直接存储值的原始类型不同,引用变量存储对对象的引用。即内存某处有一个对象,引用变量只是存储了这个对象在内存中的地址(对象的引用)。

只有基本类型将值直接存储在变量中。所有其他类型只存储一个对象引用。顺便说一下,您已经遇到过两种类型的变量——String变量和数组变量。

数组和字符串都是存储在内存中某处的对象。String变量和数组变量仅存储对对象的引用。

Java 中的引用变量

int a, int b and double d是将它们的值存储在自身内部的原始变量。

变量String str是一个引用,将地址(引用)存储到String内存中的对象。

将原始值分配给原始类型的变量时,其值被复制(复制)。分配引用变量时,仅复制对象的地址——不复制对象本身


2. 什么是参考文献?

参考变量和原始变量之间的根本区别是什么?

原始变量就像一个盒子:您可以在其中存储一些值。参考变量更像是一张上面有电话号码的纸。

汽车 vs 汽车钥匙

想象一下,您决定在朋友生日时送他一辆车。你不会把它包在一个盒子里随身携带:汽车太大了。

将车钥匙放在一个足够大的盒子里会方便得多。当他从盒子里拿出钥匙时,你的朋友就会明白一切。当您只需交出钥匙时,就无需随身携带整辆车。

一个人 vs 她的电话号码

或者这是另一个比较:一个人和她的电话号码。一个电话号码不是那个人,但是一个电话号码可以用来给她打电话,向她询问一些信息,或者提供指示。

类似地,引用用于与对象交互。所有对象都使用引用相互交互。我们不是“交换人”,而是简单地交换电话号码。

为原始变量赋值时,其值被复制(复制)。为引用变量赋值时,只会复制对象的地址(电话号码)——不会复制对象本身。

引用提供了另一个优势:您可以将对象引用传递给某个方法,该方法将能够通过使用对对象的引用、调用对象的方法和访问对象内部的数据来修改(更改)对象。


3.分配引用

分配引用变量时,只分配对象在内存中的地址。对象本身不会出现或消失。

这种方法避免了复制大量内存。如果您需要将一个非常大的对象传递给方法,我们只需传递对象引用即可。引用占用的空间要少得多。

分配参考

所有引用变量(无论其类型如何)的大小都是相同的 — 4 个字节(类似于 int)。但!如果您的应用程序在 64 位 Java 机器上运行,那么所有引用的大小都是 8 字节(64 位)。

更何况,引用只能相互赋值。您不能更改引用或为引用变量分配任意值:

代码 描述
String hello = "Hello";
String s = hello;
这是允许的
String hello = "Hello";
hello++;
但这是不允许的
String hello = 0x1234;
这是不允许的

4.null参考

如果还没有分配给它,引用变量存储什么?

它存储引用。null是一个特殊的 Java 关键字,表示没有引用(空引用)。该null值可以分配给任何引用变量。

所有引用变量都是,null除非它们已经分配了某种引用。

例子:

代码 描述
class Person
{
   public static String name;
   public static int age;
}


String name变量有一个默认值:null
int age变量有一个默认值:0

对于原始类型和引用类型,未赋值的局部变量被视为未初始化。

如果一个变量存储了对某个对象的引用,而您想清除该变量的值,则只需为其分配一个空引用即可。

代码 描述
String s = null;
s = "Hello";
s = null;
s商店null。存储对字符串对象存储的
s引用。
snull

5.传递对方法的引用

如果方法的参数是引用类型,则值将以与处理非引用变量时相同的方式传递给该方法。该参数只是简单地分配了另一个变量的值。

例子:

代码 描述
class Solution
{
   public static void fill(String[] array, String value)
   {
      for (int i = 0; i < array.length; i++)
        array[i] = value;
   }

   public static void main(String[] args)
   {
     String[] data = new String[10];
     fill(data, "Hello");
   }
}


用传递的值 ( )填充fill传递的数组( )。arrayvalue

fill调用该方法时,array参数会被分配一个对数组的引用data。该value变量被分配了对字符串对象(“Hello”)的引用。

这是调用方法之前 内存的样子fill

传递对方法的引用

这是方法运行 内存的样子fill

传递对方法 2 的引用

和变量引用(存储引用)内存中的同一容器dataarray

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。只是当我们谈论引用变量时,这个值是一个引用。