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

six*_*ude 55 java integer pass-by-reference

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

Integer i = 0;
i = i + 1;  // ? I think that this is somehow creating a new object!
Run Code Online (Sandbox Code Playgroud)

这是我的推理:我知道java是通过值传递(或通过引用值传递),所以我认为在下面的示例中,每次都应该递增整数对象.

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的预期输出:

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
...

它为什么会这样?

Bal*_*usC 55

有两个问题:

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

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

integer = inc(integer);
Run Code Online (Sandbox Code Playgroud)

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

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";
}
Run Code Online (Sandbox Code Playgroud)

  • 严格地说,对于引用它是"按值传递引用"而对于原语它只是"按值传递". (26认同)
  • 它并没有真正超越价值.它通过引用的值....因为对象传递的唯一内容是内存地址. (14认同)
  • 好吧,引用的副本被发送到函数中 (2认同)

Mar*_*kos 18

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

class WrapInt{
    int value;
}

WrapInt theInt = new WrapInt();

inc(theInt);
System.out.println("main: "+theInt.value);
Run Code Online (Sandbox Code Playgroud)

  • 为什么Integer是不可变的? (3认同)
  • @RahulJain不确定,我怀疑它是否与实际值类型(`int`)一致,因此它们都具有相同的语义。 (2认同)
  • @RahulJain`int`是`primitive`类型。基本类型是不可变的。我怀疑您将“ final”关键字与不变性相混淆-它们是不同的东西。您可以更改Integer变量的引用(与int变量的值相同)。它们几乎是一致的。 (2认同)

Ris*_*Dua 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
1
7
7
Run Code Online (Sandbox Code Playgroud)


小智 15

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

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

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

import java.util.concurrent.atomic.AtomicInteger
Run Code Online (Sandbox Code Playgroud)


rsp*_*rsp 12

你在这里看到的不是一个重载的+oparator,而是自动装箱行为.该Integer班是不可改变的,你的代码:

Integer i = 0;
i = i + 1;  
Run Code Online (Sandbox Code Playgroud)

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

Integer i = Integer.valueOf(0);
i = Integer.valueOf(i.intValue() + 1);  
Run Code Online (Sandbox Code Playgroud)

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


use*_*421 6

你在这里是对的:

Integer i = 0;
i = i + 1;  // <- I think that this is somehow creating a new object!
Run Code Online (Sandbox Code Playgroud)

第一:整数是不可变的.

第二:Integer类没有覆盖+运算符,在该行中涉及自动装箱和自动装箱(在旧版本的Java中,您会在上面的行中收到错误).
编写i + 1编译器时,首先将Integer转换为(基元)int以执行添加:autounboxing.接下来,i = <some int>编译器将转换int为(新)Integer:autoboxing.
所以+实际上是应用于原始ints.