更新参考变量
Update of reference variable
想问一下,两个例子的区别在哪里:
class PassA
{
public static void main(String [] args)
{
PassA p = new PassA();
p.start();
}
void start()
{
long [] a1 = {3,4,5};
long [] a2 = fix(a1);
System.out.print(a1[0] + a1[1] + a1[2] + " ");
System.out.println(a2[0] + a2[1] + a2[2]);
}
long [] fix(long [] a3)
{
a3[1] = 7;
return a3;
}
}
在上面的代码中:
- 引用变量a1和a3引用同一个长数组
目的。当 [1] 元素在 fix() 方法中更新时,它是
更新 a1 引用的数组。参考变量a2
引用同一个数组对象。所以输出:3+7+5+" "3+7+5
但在下面的代码中
class Test
{
public static void main(String [] args)
{
Test p = new Test();
p.start();
}
void start()
{
boolean b1 = false;
boolean b2 = fix(b1);
System.out.println(b1 + " " + b2);
}
boolean fix(boolean b3)
{
b3 = true;
return b3;
}
}
- fix() 方法中的布尔值 b1 与
b1 在 start() 方法中。 start() 方法中的 b1 不是
通过 fix() 方法更新。
问题
有什么区别?我怎样才能更改代码(示例 1)以使 a1
不会被更改?
图纸
a1 => Long object ID 9999: [3, 4, 5]
a3 => Long object ID 9999: [3, 4, 5] (ie. same object)
然后你做
a3[1] = 7;
我们取消引用 a3
并得到
Long object ID 9999: [primitive long value: 3, primitive long value: 4, primitive long value: 5]
然后我们访问索引 1 处的元素并将其值更改为 7
Long object ID 9999: [primitive long value: 3, primitive long value: 7, primitive long value: 5]
第二种情况
b1 = primitive boolean value: false
b3 = primitive boolean value: false (no relation to the other, just another false)
然后你做
b3 = true;
这只会改变 b3
b3 = primitive boolean value: true (still no relation)
这是因为Java is a pass-by-value language.
要更改您的第一个代码段,您必须复制数组并在调用该方法时传递该副本。
在 Java 中,一切都按值传递,包括对象引用。在这两种情况下,都会制作参数 a3
或 b3
的副本。但是,对象引用的副本继续引用同一对象,而基元的副本与原始对象完全断开连接。
要使第一个示例的行为与第二个示例相同,请在修改数组(它是引用类型对象)之前创建一个 副本:
long [] fix(long [] a3)
{
long[] res = Arrays.copyOf(a3, a3.length);
res[1] = 7;
return res;
}
Java 按值传递,这意味着只有原始副本被传递到方法中。然而,区别在于:
参考下面经典的bad-swap例子:
public void badSwap(int var1, int var2)
{
int temp = var1;
var1 = var2;
var2 = temp;
}
在这里,这是一个 badSwap,因为 var1 和 var2 保持不变。在函数内仅交换这些整数的副本。
现在,当在您的示例中复制您的 'al' 数组引用时,'al' 的副本仍然引用您的原始 {3, 4, 5} 数组。
因此,当您执行以下操作时:
long [] a1 = {3,4,5};
long [] a2 = fix(a1);
a3[1] = 7 in the fix(al) method changes the value of the original al.
相反,传入数组本身的副本。
要记住的要点:
引用的副本仍然指向同一事物,而原始类型(int、boolean..)的副本与原始类型完全不同。
在 Java 中,一切都按值传递(参见 here)。
基本上,变量传递给函数有三种情况:
- 原始类型(boolean、byte、short、int、long、float、double、char)
- 不可变对象(例如字符串)
- 可变对象(注意本机数组,即使是基本类型,也是可变的,所以值是对数组的引用)
对于前两种情况,内容没有改变(例如您的示例 2 传递了一个布尔值)
在第三种情况下,可以更改内容(例如您的示例 1 传递了一个 long[])。
那么,如何不改变示例 1 中的 long[]?原始数组是不可能的(除非您使用 for 循环在函数内创建另一个数组,将输入的所有项目复制到这个新数组,然后对该副本进行操作)。或者在调用函数之前创建初始数组的副本,并以此副本作为输入来调用函数。
除了将所有内容复制到另一个数组之外,不可变的原生原始数组是不存在的。您需要使用 List 或其他一些数据结构:您需要使用列表或其他一些数据结构(参见 here)
想问一下,两个例子的区别在哪里:
class PassA
{
public static void main(String [] args)
{
PassA p = new PassA();
p.start();
}
void start()
{
long [] a1 = {3,4,5};
long [] a2 = fix(a1);
System.out.print(a1[0] + a1[1] + a1[2] + " ");
System.out.println(a2[0] + a2[1] + a2[2]);
}
long [] fix(long [] a3)
{
a3[1] = 7;
return a3;
}
}
在上面的代码中:
- 引用变量a1和a3引用同一个长数组 目的。当 [1] 元素在 fix() 方法中更新时,它是 更新 a1 引用的数组。参考变量a2 引用同一个数组对象。所以输出:3+7+5+" "3+7+5
但在下面的代码中
class Test
{
public static void main(String [] args)
{
Test p = new Test();
p.start();
}
void start()
{
boolean b1 = false;
boolean b2 = fix(b1);
System.out.println(b1 + " " + b2);
}
boolean fix(boolean b3)
{
b3 = true;
return b3;
}
}
- fix() 方法中的布尔值 b1 与 b1 在 start() 方法中。 start() 方法中的 b1 不是 通过 fix() 方法更新。
问题
有什么区别?我怎样才能更改代码(示例 1)以使 a1
不会被更改?
图纸
a1 => Long object ID 9999: [3, 4, 5]
a3 => Long object ID 9999: [3, 4, 5] (ie. same object)
然后你做
a3[1] = 7;
我们取消引用 a3
并得到
Long object ID 9999: [primitive long value: 3, primitive long value: 4, primitive long value: 5]
然后我们访问索引 1 处的元素并将其值更改为 7
Long object ID 9999: [primitive long value: 3, primitive long value: 7, primitive long value: 5]
第二种情况
b1 = primitive boolean value: false
b3 = primitive boolean value: false (no relation to the other, just another false)
然后你做
b3 = true;
这只会改变 b3
b3 = primitive boolean value: true (still no relation)
这是因为Java is a pass-by-value language.
要更改您的第一个代码段,您必须复制数组并在调用该方法时传递该副本。
在 Java 中,一切都按值传递,包括对象引用。在这两种情况下,都会制作参数 a3
或 b3
的副本。但是,对象引用的副本继续引用同一对象,而基元的副本与原始对象完全断开连接。
要使第一个示例的行为与第二个示例相同,请在修改数组(它是引用类型对象)之前创建一个 副本:
long [] fix(long [] a3)
{
long[] res = Arrays.copyOf(a3, a3.length);
res[1] = 7;
return res;
}
Java 按值传递,这意味着只有原始副本被传递到方法中。然而,区别在于:
参考下面经典的bad-swap例子:
public void badSwap(int var1, int var2)
{
int temp = var1;
var1 = var2;
var2 = temp;
}
在这里,这是一个 badSwap,因为 var1 和 var2 保持不变。在函数内仅交换这些整数的副本。
现在,当在您的示例中复制您的 'al' 数组引用时,'al' 的副本仍然引用您的原始 {3, 4, 5} 数组。
因此,当您执行以下操作时:
long [] a1 = {3,4,5};
long [] a2 = fix(a1);
a3[1] = 7 in the fix(al) method changes the value of the original al.
相反,传入数组本身的副本。
要记住的要点:
引用的副本仍然指向同一事物,而原始类型(int、boolean..)的副本与原始类型完全不同。
在 Java 中,一切都按值传递(参见 here)。
基本上,变量传递给函数有三种情况:
- 原始类型(boolean、byte、short、int、long、float、double、char)
- 不可变对象(例如字符串)
- 可变对象(注意本机数组,即使是基本类型,也是可变的,所以值是对数组的引用)
对于前两种情况,内容没有改变(例如您的示例 2 传递了一个布尔值)
在第三种情况下,可以更改内容(例如您的示例 1 传递了一个 long[])。
那么,如何不改变示例 1 中的 long[]?原始数组是不可能的(除非您使用 for 循环在函数内创建另一个数组,将输入的所有项目复制到这个新数组,然后对该副本进行操作)。或者在调用函数之前创建初始数组的副本,并以此副本作为输入来调用函数。
除了将所有内容复制到另一个数组之外,不可变的原生原始数组是不存在的。您需要使用 List 或其他一些数据结构:您需要使用列表或其他一些数据结构(参见 here)