如何通过引用正确传递Integer类?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何通过引用正确传递Integer类?相关的知识,希望对你有一定的参考价值。
我希望有人可以为我澄清这里发生的事情。我在整数类中挖了一下但由于整数覆盖了+
运算符,我无法弄清楚出了什么问题。我的问题在于这一行:
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 ...
它为什么会这样?
有两个问题:
- 整数是按值传递的,而不是通过引用传递的。更改方法内的引用不会反映到调用方法中的传入引用中。
- 整数是不可变的。没有像
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";
}
整数是不可变的。您可以在自定义包装类中包装int。
class WrapInt{
int value;
}
WrapInt theInt = new WrapInt();
inc(theInt);
System.out.println("main: "+theInt.value);
有两种方法可以通过引用传递
- 使用Apache Commons库中的org.apache.commons.lang.mutable.MutableInt。
- 创建自定义类,如下所示
这是一个示例代码:
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
上面的答案很好地解释了OP的实际问题。
如果有人需要传递需要全局更新的数字,请使用AtomicInteger(
)而不是创建建议的各种包装类或依赖第三方库。
AtomicInteger(
)当然主要用于线程安全访问,但如果性能不受影响,为什么不使用这个内置类。额外的好处当然是明显的线程安全性。
import java.util.concurrent.atomic.AtomicInteger
你在这里看到的不是一个超载的qazxsw poi操作符,而是自动装箱行为。 qazxsw poi类是不可变的,你的代码:
+
编译器(在自动装箱后)看到:
Integer
所以你的结论是正确的,Integer i = 0;
i = i + 1;
实例是改变的,但不是偷偷摸摸的 - 它与Java语言定义一致:-)
你在这里是对的:
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>
实际上被应用于原始的int
s。
我认为是自动装箱会让你失望。
这部分代码:
+
真的归结为代码看起来像:
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;
}
如果您将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);
}
}
相反,它是通过自动装箱完成的。
以上是关于如何通过引用正确传递Integer类?的主要内容,如果未能解决你的问题,请参考以下文章