【问题标题】:function won't change value of variable in java?函数不会改变java中变量的值?
【发布时间】:2015-08-30 05:52:29
【问题描述】:

我知道 java 中的所有内容都是按值传递的,但下面的代码不应该打印 2 而不是 1。

我所做的只是传递Integer 并更改其值。为什么打印 1 而不是 2 ?

public static Integer x;

public static void doChange(Integer x) {
    x = 2;
}

public static void main(String arg[]) {
    x = 1;
    doChange(x);
    System.out.println(x);
}

【问题讨论】:

  • doChange中,x是参数变量,而不是全局静态x。
  • 但是参数变量指向全局静态变量。
  • 你从哪里学来的?指向全局变量的参数?
  • 为什么要将参数x 传递给doChange()。您可以简单地修改x 而不将其作为参数传递,您的意图到底是什么?
  • 我在一次采访中被问到这个问题。

标签: java variables static


【解决方案1】:

非常感谢您的回答。我想我现在知道幕后发生了什么。我认为我无法看到主函数变化的原因是因为整数是不可变的,当我为它分配新值时,它会创建新对象并分配给引用 x;

如果我们可以使用可变数据重复相同的示例,我们将看到不同的输出。

public static StringBuilder x;

public static void doChange(StringBuilder x)

{

    x.append("world");

}

public static void main(String arg[]) {
    x = new StringBuilder("hello ");

    doChange(x);

    System.out.println(x);
}

输出:你好世界

【讨论】:

    【解决方案2】:

    加框的int 仍然是不可变的,doChange 中的x 指的是参数,而不是字段。为了显示发生了什么,这里是您的代码的明确装箱版本。

    public static Integer x;
    
    // parameter 'x' is hiding field 'x'
    public static void doChange(Integer x)
    {
        // Update parameter 'x', not field 'x', to point to
        // new Integer object with value 2.
        // Since 'x' is by-value, caller will not see change
        x = Integer.valueOf(2);
    }
    
    public static void main(String arg[]) {
        x = Integer.valueOf(1);
        doChange(x);
        System.out.println(x);
    }
    

    【讨论】:

      【解决方案3】:

      你回答了你自己的问题:)。

      由于它是按值传递的,所以 doChange() 方法将具有 value 的副本。因此,无论它在该方法中做什么,它都不会影响在 main 方法中声明的实际“x”变量。

      【讨论】:

        【解决方案4】:

        这就是您在代码中解决问题的方法。我创建了一个名为La 的类。注意doChange() 方法中的La.x = 2; 语句。

        public class La {
        
            public static Integer x;
        
            public static void doChange(Integer x) {
                La.x = 2;
            }
        
            public static void main(String arg[]) {
                x = 1;
                doChange(x);
                System.out.println(x);
            }
        }
        

        【讨论】:

          【解决方案5】:

          你改变了你的参数,而不是你的类变量。重命名您的参数,它将起作用:

          public static void doChange(Integer unused)
          {
              x = 2;
          }
          

          原因是您通过赋值 (=) 更改了实例。您的参数 x 被分配给一个新实例(而不是您通过方法调用给它的那个)。解决方案是调用实例方法来改变实例的状态。但: 标量的对象类不像其他类那样工作。 Integer 的实例是唯一的(不可变的),您不能更改 Integer 实例的状态。

          但是,如果您尝试使用自己的类(如 MyNumber)并使用实例方法调用(而不是赋值 =),它将按您的预期工作:

          public class MyNumber {
              private int number = 0;
              public set(int v) {
                  number = v;
              }
              public get() {
                  return number;
              }
              public String toString() {
                  return Integer.toString(number);
              }
          }
          

          如果您使用 MyNumber 而不是 Integer,请将您的方法 doChange 更改为:

          public static void doChange(MyNumber x)
          {
              x.set(2);
          }
          

          当然还有将声明更改为:

          public static MyNumber x;
          

          ... 和 main 中的第一个任务:

          x.set(1);
          

          希望对理解有所帮助。

          【讨论】:

            【解决方案6】:

            您正在将一个对象 Integer 传递给 doChange 函数。在 doChange() 中,您正在分配一个新值,而 Java 正在自动装箱,即创建一个值为 2 的新 Integer 对象并将您的参数指向它。

            指向对象的变量基本上是指向内存地址的指针:请参阅以下答案:https://stackoverflow.com/a/1750197/2698109https://stackoverflow.com/a/1750141/2698109

             public static Integer x; // an primitive Object
            
             // passing an object
             public static void doChange(Integer x) { 
                // under the hood Java is doing this
                x = new Integer(2);
             } 
            

            将您的方法签名更改为

            public static void doChange(int x) {
            

            它应该按预期工作。

            【讨论】:

            • 其实这不是自动装箱。自动装箱将直接将 into 分配给 Integer 对象。例如:整数 x = 2;这会将 2 自动装箱到整数对象。但是 Integer x = new Integer(2) 正在通过 Integer 包装器的构造函数创建一个对象。不会发生自动装箱。简而言之,自动装箱涉及将原始数据类型分配给该数据类型的对象包装器。布尔 boo = true;是自动装箱。 Boolean boo = new Boolean(true) 不是自动装箱。 doChange(5) 自动装箱到 doChange (new Integer(5));自动地。 int x = new Integer(5) 不是自动装箱。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-10-29
            • 1970-01-01
            • 1970-01-01
            • 2015-06-17
            • 1970-01-01
            相关资源
            最近更新 更多