更新参考变量

时间:2015-01-01 15:36:15

标签: java

我想问一下,两个例子的区别在哪里:

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;
    }
}

在上面的代码中:

  1. 引用变量a1和a3指的是同一个长数组 宾语。在fix()方法中更新[1]元素时,它是 更新a1引用的数组。参考变量a2 指的是同一个数组对象。所以输出:3 + 7 + 5 +“”3 + 7 + 5
  2. 但在下面的代码中

    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;
        }
    }
    
    1. fix()方法中的布尔值b1与布尔值不同 b1在start()方法中。 start()方法中的b1不是 由fix()方法更新。
    2. 问题

      有什么区别?如何更改代码(示例1)以便{?1}}不会被更改?

4 个答案:

答案 0 :(得分:1)

附图

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

要更改第一个代码段,您必须复制数组并在调用方法时传递该副本。

答案 1 :(得分:1)

在Java中,所有内容都按值传递,包括对象引用。在这两种情况下,都会生成参数a3b3的副本。但是,对象引用的副本继续引用同一对象,而基元的副本与原始对象完全断开。

要使第一个示例与第二个示例相同,请在修改之前创建数组的副本(这是一个引用类型对象):

long [] fix(long [] a3) 
{
    long[] res = Arrays.copyOf(a3, a3.length);
    res[1] = 7;
    return res;
}

答案 2 :(得分:1)

在Java中,所有内容都按值传递(参见here)。

基本上,有三种变量传递给函数:

  1. 原始类型(boolean,byte,short,int,long,float,double,char)
  2. 不可变对象(如字符串)
  3. 可变对象(请注意,本机数组,即使是基本类型,也是可变的,因此值是对数组的引用)
  4. 对于前两种情况,内容不会改变(例如你的例子2传递一个布尔

    在第三种情况下,内容可以改变(例如你的例子1通过long [] )。

    那么,如何不改变示例1中的long []?原始数组是不可能的(除非你在函数内创建另一个数组,使用for循环将输入的所有项复制到这个新数组,然后对这个副本进行操作)。或者在调用函数之前创建初始数组的副本,并使用此副本作为输入调用该函数。

    除了将所有内容复制到另一个数组外,不存在不可变的本机原始数组。您需要使用List或其他一些数据结构:您需要使用List或其他一些数据结构(请参阅here

答案 3 :(得分:0)

Java按值传入,意味着只将原始副本传递给方法。但是,这就是区别:

请参阅下面的经典不良交换示例:

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 ..)的副本与原始文本完全分开。