JDK 5引进了很多新的特性,其中有一个就是自动装箱(Autoboxing)和自动拆箱(Auto-Unboxing)。 在k++的时候就等于k=k+1; 再翻译为k=Integer.valueOf(Integer.valueOf(k)+1); 再看看java.lang.Integer中关于valueOf的源代码是怎样的: public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); } 在这里k就指到了另外的一个对象,所以他的直在改变没有影响到原来的值~`
要实现,拿个对象包一下就行了 public class Main { private Integer k; static void Intk(Main m) { m.k++; } public static void main(String[] args) { Main m = new Main(); m.k = new Integer(1); Intk(m); System.out.print(m.k); } }
++k;
System.out.println(k);
return k;
} public static void main(String[] args)
{
int k=0;
k= Intk(k);
System.out.print(k); }
VOID和INT的区别
你看看你传进的K在Intk方法是加1啦
但是你main函数里打印的还是你Integer k=new Integer(1);
所赋的初值
1.基本类型为值传递.2.类对象传递其引用的复制.3.String类型以及所有的基本类型的包装类有特殊情况,因为不可变类和常数池的机制,他们的引用改变不了他们所指向的对象的值。只有将改变后的对象作为返回值才能得到改变后的对象。楼主的问题参见第三点.
在k++的时候就等于k=k+1;
再翻译为k=Integer.valueOf(Integer.valueOf(k)+1);
再看看java.lang.Integer中关于valueOf的源代码是怎样的:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
在这里k就指到了另外的一个对象,所以他的直在改变没有影响到原来的值~`
一旦其值发生改变:
Java会查找对应的常量池,如果常量池中存在改变后的对象,那么Java会复制一个并将该引用指向复制的那个对象.
如果常量池不存在改变后的对象,Java会先在池中建立一个,然后再复制一个并将该引用指向复制的那个对象.所以楼主原代码中:
Intk中的k和main中的k都指向1.
k++之后,main的k指向1,不过Intk中k的指向被改变,它其实指向一个新的Integer对象2.
最后打印main中的k,结果当然为1.解决办法如1楼,使用return,覆盖main中的k,使其指向2.
public class Main { private Integer k; static void Intk(Main m) {
m.k++;
} public static void main(String[] args) {
Main m = new Main();
m.k = new Integer(1);
Intk(m);
System.out.print(m.k);
}
}
问题应该和自动装箱无关,我在JDK1.4中测试楼主代码,结果依然是1...
我认为主要原因还是String和包装类的特殊情况喵~~~~`
static void Intk(Integer k){
k++;
}
这种写法就报错
编译都通不过,你的jdk1.4这么强?
不过我坚持k不改变同拆包无关,那几个类特殊而已.它直接改变引用而不改变对象.
是啊,LZ 是代码能通过编译啊?我怎么不能通过啊? (Integer) k++ ,这也行??!!~~~
看看字节码就清楚了 public void view() {
Integer k = new Integer(1);
k++;
}
字节码为:
public void view();
Code:
0: new #2; //class java/lang/Integer
3: dup
4: iconst_1
5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V
8: astore_1
9: aload_1
10: astore_2
11: aload_1
12: invokevirtual #4; //Method java/lang/Integer.intValue:()I
15: iconst_1
16: iadd
17: invokestatic #5; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
20: dup
21: astore_1
22: astore_3
23: aload_2
24: pop
25: return
当中就掉用了Integer.valueOf();
所以k++是和k=Integer.valueOf(Integer.valueOf(k)+1);效果是一样的。再看看Integer.valueOf的源码`
ps:jdk1.4会报错说不能从Integer转化为int的,
1.5版本以下都不能long=Long,int=Integer .... 转
5楼的例子其实也很明显了,任何妄图改变k值的操作,Java都会new一个新的出来...5楼的解释也很正确...楼主代码之所以没报错,是拆包的缘故,换1.4写的话,楼主就不会有疑惑了.
刚才我在Eclipse里测试的,虽然选了1.4不过有新特性会自动容错.回13楼,同意你的看法,其实正是这些代码体现了不可变类的特点,一旦发生改变,引用将指向新对象.
public class Pass {
String a="123";
public static void test(Pass passA) {
passA.a="abc";
}
public static void main(String[] args) {
Pass passB=new Pass();
passB.a= "123";
System.out.println(passB.a);
test(passB);
System.out.println(passB.a);
}
}
结果是:
123
abc 所有的参数传递都是 传值,从来没有 传引用 这个事实。
所有的参数传递都会在 程序运行栈上 新分配一个 值 的复制品. 如果把
public static void test(Pass passA) {
passA.a="abc";
} 改成
public static void test(Pass passA) {
passA = null;
}看看, 对passA有什么影响?
毫无作用。函数调用出来后,passA还是原来的值,不会变成Null. 这个传的 PassA 的 地址值。这个 地址值 被复制了一份。
static void Intk(Integer k){
k++;
}
public static void main(String[] args){
Integer k=new Integer(1);
Intk(k);
System.out.print(k);
}
}
这个程序中也是传入的是Integer k地址值(复制值),而且是复制了一份给Intk()函数,在Intk()里面改变的是Integer k复制值,在函数外面没有改变