为什么这一个变量会受到影响?

时间:2011-12-23 22:44:48

标签: java variables scope

这是我在StackOverflow的第一个问题。这是有问题的代码:

public class ListStuff {
  public static void main(String [] args) {

    String[] randomNames = {"Herbie", "Jaco", "Pat", "Michael"};        
    String[] reversedNames = revertNames(randomNames);

    for (int i = 0; i < reversedNames.length; i++) {
        System.out.println(reversedNames[i]);
    }   
  }

  public static String[] revertNames(String[] s) {

    for (int i = 0; i < s.length / 2; i++) {
       String tmp = s[s.length - 1 - i];
       s[s.length - 1 - i] = s[i];
       s[i] = tmp;
    }  

  return s;
  }
}

此代码运行良好,reversedNames变量打印为已恢复;没有抱怨。然而,我主要担心的是,当我执行String[] reversedNames = revertNames(randomNames);时,变量randomNames也会被还原。我没做任何地方用randomNames改变randomNames = blabla;变量,所以我不明白为什么该变量不断变换为自身的恢复版本,即使我只是将它作为参数传递。

我已经编程了大约一年,而且我对变量范围的了解非常有限。有人能指出我正确的方向吗?

5 个答案:

答案 0 :(得分:7)

Java中的数组是引用类型。这意味着当您将数组传递给revertNames方法时,该方法内部的任何更改也将在外部看到。由于您要使用以下代码更改s内的数组参数revertNames

String tmp = s[s.length - 1 - i];
s[s.length - 1 - i] = s[i];
s[i] = tmp;

代替randomNames传递的原始数组s也会在此过程中发生变化。

答案 1 :(得分:3)

这是因为您通过引用而不是按值传递数组。从本质上讲,这意味着reversedNames数组仍然指向randomNames数组,因此更改一个数组会改变另一个数组。

以下是变量图:

最初:

randomNames

当我们输入revertNames函数时:

randomNames <-------- s

s数组仍然指向randomNames数组!因此,当我们更改s时,我们也会更改randomNames

当我们离开这个职能部门时:

randomNames <--------- s <--------- reversedNames

因此,reversedNames指向randomNames

函数调用完成后:

randomNames <--------- reversedNames

虽然s数组已消失,但reversedNames仍指向randomNames

要解决此问题,请在revertNames函数中创建一个临时变量:

public static String[] revertNames(String[] oldarray) {
    // Create temporary array to avoid affecting original array
    String[] s = oldarray.clone();
    ...

答案 2 :(得分:1)

在revertNames的主体中,你有一个变量s,这是对一个数组的对象的引用。实际的数组是数组randomNames。所以你确实在改变源数组中的值。

如果你使用Arrays.copy()你可以得到一个独立的数组 - 副本将指向与原始数组相同的字符串,但是因为字符串是可以安全的,所以

答案 3 :(得分:0)

您可以使用:StringBuffer:reverse()

有些事情是这样的:

public class t {
  public static void main(String [] args) {

    String[] randomNames = {"Herbie", "Jaco", "Pat", "Michael"};        
    StringBuffer rev;
    for (int i = 0; i < randomNames.length; i++) 
    {
       rev=new StringBuffer(randomNames[i]);
        System.out.println(rev.reverse().toString());
    }   
  }
}

答案 4 :(得分:0)

Java中的数组是引用类型,即如果声明

String[] randomNames;

您已声明一个局部变量,该变量包含对作为字符串数组的对象的引用。

声明

String[] otherNames = randomNames;

会将变量randomNames的内容复制到变量otherNames,但内容只是一个引用。也就是说,此语句会导致otherNames和randomNames引用同一个数组对象。

当您传递String[]作为方法参数时,会发生同样的情况。也就是说,s中的局部变量revertNamesrandomNames中的局部变量main将包含相同的引用,即引用相同的数组对象。也就是说,虽然srandomNames都可以看到该数组对象的状态。

严格来说,这与范围无关,因为变量randomNames未被修改(即它仍然指向同一个数组)。修改的是它引用的对象。