ー:题目如下
public
class
IntegerSwapTest
{
public
static
void
main
(
String
[]
args
) {
Integer
a
=
1
;
Integer
b
=
2
;
System
.
out
.
println
(
"before swap: a="
+
a
+
",b="
+
b
);
swap
(
a
,
b
);
System
.
out
.
println
(
"after swap: a="
+
a
+
",b="
+
b
);
}
//
TODO
交换两个integer的值
private
static
void
swap
(
Integer
integer1
,
Integer
integer2
) {
}
}
二:我们刚开始想到的肯定是依赖第三方变量,因为integer是包装类(原以为他传递的是引用)
//
TODO
交换两个integer的值
private
static
void
swap
(
Integer
integer1
,
Integer
integer2
) {
Integer
temp
=
integer1
;
integer1
=
integer2
;
integer2
=
temp
;
}
结果为:妈耶没变这怎么搞
before swap: a=1,b=2
after swap: a=1,b=2
三:java中两种传值模式: ①引用传递 ②值传递 不过这两种传递的都是副本
integer类是final不允许有子类,且在创建对象的时候要不新建要不就在缓存中拿,并且value的字段是私有也没有提供getter方法
可以使用javap来查看到底调用的class中的哪种方法
public class Test{
public static void main(String[] args){
Integer a = 1;
int b = a;
}
}
PS C:\Users\xxx\Desktop> javap -c Test
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: aload_1
6: invokevirtual #3 // Method java/lang/Integer.intValue:()I
9: istore_2
10: return
}
可知自动装箱调用的是valueOf方法,而自动拆箱调用的是intValue方法(该方法类似于get方法)
public
int
intValue
() {
return
value
;
}
四:于是我们使用反射来解决这个问题
//
TODO
交换两个integer的值
private
static
void
swap
(
Integer
integer1
,
Integer
integer2
) {
try
{
Field
valueField
=
Integer
.
class
.
getDeclaredField
(
"value"
);
valueField
.
setAccessible
(
true
);
int
temp
=
integer1
.
intValue
();
valueField
.
set
(
integer1
,
integer2
);
valueField
.
set
(
integer2
,
temp
);
}
catch
(
Exception
e
) {
//
TODO
Auto-generated catch block
e
.
printStackTrace
();
}
}
before swap: a=1,b=2
after swap: a=2,b=2
因为对象都是公用的一份字节码文件,value变为可变的之后,即内存中Integer对象会都变为value可变,包括在IntegerCache.cache[]中的缓存都会改变
于是
0.int temp = 1;
1.integer1中的value变为2(IntegerCache.cache[131]),即IntegerCache.cache[130]变为2;
2.integer2中的value调用set的时候,会先把1转为Integer(IntegerCache.cache[130])的再取得他的intValue()值,则还是2;
UnsafeQualifiedIntegerFieldAccessorImpl.class
五:解决方法
〇:只要不在缓存池里就不存在这个问题
①:再新new一个1的Integer
int
temp
=
integer1
.
intValue
();
valueField
.
set
(
integer1
,
integer2
);
valueField
.
set
(
integer2
,
new
Integer
(
temp
));
②:使用指定的方法setInt()
int
temp
=
integer1
.
intValue
();
valueField
.
set
(
integer1
,
integer2
);
valueField
.
setInt
(
integer2
,
temp
);
③:从一位大哥那里学到的(最终解法)
//
TODO
交换两个integer的值
private
static
void
swap
(
Integer
integer1
,
Integer
integer2
) {
System
.
out
.
println
(
"after swap: a=2,b=1"
);
}