【问题标题】:Why is this one variable being affected?为什么这一变量会受到影响?
【发布时间】:2011-12-23 22:44:48
【问题描述】:

这是我在 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 = blabla; 更改randomNames 变量,所以我看不出为什么该变量不断更改为自身的还原版本,即使我只是将它作为参数传递。

我已经编程了大约一年,我对变量作用域等的了解非常有限。谁能指出我正确的方向?

【问题讨论】:

    标签: java variables scope


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      那是因为您通过引用而不是值传递数组。本质上,这意味着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();
          ...
      

      【讨论】:

      • 哇。有史以来最快的反应,伟大的回答者,我会研究这个并尝试变化=)
      • 我现在改变了我的投票......最初的回应没有提供任何关于这个问题的见解。 +1
      【解决方案3】:

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

      如果你使用 Arrays.copy() 你可以得到一个独立的数组来工作 - 副本将指向与原始数组相同的字符串,但由于字符串是不可变的,所以这是安全的。

      【讨论】:

        【解决方案4】:

        你可以使用: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());
            }   
          }
        }
        

        【讨论】:

          【解决方案5】:

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

          String[] randomNames;
          

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

          声明

          String[] otherNames = randomNames;
          

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

          当您将String[] 作为方法参数传递时,也会发生同样的情况。也就是说,revertNames 中的局部变量smain 中的局部变量randomNames 将包含相同的引用,即引用相同的数组对象。也就是说,该数组对象的状态将通过srandomNames 可见。

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

          【讨论】:

            猜你喜欢
            • 2017-01-14
            • 2023-03-03
            • 2020-08-14
            • 2022-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多