如何通过引用正确传递Integer类?

问题描述 投票:52回答:8

我希望有人可以为我澄清这里发生的事情。我在整数类中挖了一下但由于整数覆盖了+运算符,我无法弄清楚出了什么问题。我的问题在于这一行:

Integer i = 0;
i = i + 1;  // ← I think that this is somehow creating a new object!

这是我的推理:我知道java是按值传递的(or pass by value of reference),所以我认为在下面的例子中,每次都应该增加整数对象。

public class PassByReference {

    public static Integer inc(Integer i) {
        i = i+1;    // I think that this must be **sneakally** creating a new integer...  
        System.out.println("Inc: "+i);
        return i;
    }

    public static void main(String[] args) {
        Integer integer = new Integer(0);
        for (int i =0; i<10; i++){
            inc(integer);
            System.out.println("main: "+integer);
        }
    }
}

这是我的预期输出:

Inc: 1
main: 1
Inc: 2
main: 2
Inc: 3
main: 3
Inc: 4
main: 4
Inc: 5
main: 5
Inc: 6
main: 6
...

这是实际输出。

Inc: 1
main: 0
Inc: 1
main: 0
Inc: 1
main: 0
...

它为什么会这样?

java integer pass-by-reference
8个回答
54
投票

有两个问题:

  1. 整数是按值传递的,而不是通过引用传递的。更改方法内的引用不会反映到调用方法中的传入引用中。
  2. 整数是不可变的。没有像Integer#set(i)这样的方法。否则你可以利用它。

要使其工作,您需要重新分配inc()方法的返回值。

integer = inc(integer);

要了解更多关于传递值的信息,这是另一个例子:

public static void main(String... args) {
    String[] strings = new String[] { "foo", "bar" };
    changeReference(strings);
    System.out.println(Arrays.toString(strings)); // still [foo, bar]
    changeValue(strings);
    System.out.println(Arrays.toString(strings)); // [foo, foo]
}
public static void changeReference(String[] strings) {
    strings = new String[] { "foo", "foo" };
}
public static void changeValue(String[] strings) {
    strings[1] = "foo";
}

18
投票

整数是不可变的。您可以在自定义包装类中包装int。

class WrapInt{
    int value;
}

WrapInt theInt = new WrapInt();

inc(theInt);
System.out.println("main: "+theInt.value);

15
投票

有两种方法可以通过引用传递

  1. 使用Apache Commons库中的org.apache.commons.lang.mutable.MutableInt
  2. 创建自定义类,如下所示

这是一个示例代码:

public class Test {
    public static void main(String args[]) {
        Integer a = new Integer(1);
        Integer b = a;
        Test.modify(a);
        System.out.println(a);
        System.out.println(b);

        IntegerObj ao = new IntegerObj(1);
        IntegerObj bo = ao;
        Test.modify(ao);
        System.out.println(ao.value);
        System.out.println(bo.value);
    }


    static void modify(Integer x) {
        x=7;
    }
    static void modify(IntegerObj x) {
        x.value=7;
    }   
}

class IntegerObj {
    int value;
    IntegerObj(int val) {
        this.value = val;
    }
}

输出:

1
1
7
7

14
投票

上面的答案很好地解释了OP的实际问题。

如果有人需要传递需要全局更新的数字,请使用AtomicInteger()而不是创建建议的各种包装类或依赖第三方库。

AtomicInteger()当然主要用于线程安全访问,但如果性能不受影响,为什么不使用这个内置类。额外的好处当然是明显的线程安全性。

import java.util.concurrent.atomic.AtomicInteger

12
投票

你在这里看到的不是一个超载的qazxsw poi操作符,而是自动装箱行为。 qazxsw poi类是不可变的,你的代码:

+

编译器(在自动装箱后)看到:

Integer

所以你的结论是正确的,Integer i = 0; i = i + 1; 实例是改变的,但不是偷偷摸摸的 - 它与Java语言定义一致:-)


6
投票

你在这里是对的:

Integer i = Integer.valueOf(0);
i = Integer.valueOf(i.intValue() + 1);  

第一:整数是不可变的。

第二:Integer类没有覆盖Integer运算符,在该行中涉及自动装箱和自动装箱(在旧版本的Java中,您将在上面的行中收到错误)。 当您编写Integer i = 0; i = i + 1; // <- I think that this is somehow creating a new object! 时,编译器首先将Integer转换为(primitive)+以执行添加:autounboxing。接下来,做i + 1,编译器从int转换为(new)Integer:autoboxing。 所以i = <some int>实际上被应用于原始的ints。


2
投票

我认为是自动装箱会让你失望。

这部分代码:

+

真的归结为代码看起来像:

int

当然......不会改变传入的引用。

你可以用这样的东西修复它

   public static Integer inc(Integer i) {
        i = i+1;    // I think that this must be **sneakally** creating a new integer...  
        System.out.println("Inc: "+i);
        return i;
    }

2
投票

如果您将inc()函数更改为此

  public static Integer inc(Integer i) {
        i = new Integer(i) + new Integer(1);      
        System.out.println("Inc: "+i);
        return i;
    }

然后你会看到它总是打印“假”。这意味着添加创建了一个新的Integer实例并将其存储在局部变量i(“local”,因为我实际上是传递的引用的副本),使调用方法的变量保持不变。

Integer是一个不可变类,意味着你不能改变它的值,但必须获得一个新实例。在这种情况下,您不必像以下那样手动执行此操作:

  public static void main(String[] args) {
        Integer integer = new Integer(0);
        for (int i =0; i<10; i++){
            integer = inc(integer);
            System.out.println("main: "+integer);
        }
    }

相反,它是通过自动装箱完成的。

© www.soinside.com 2019 - 2024. All rights reserved.