话不多说,直接上例子:
public class test {
public static void main(String[] args){
System.out.println(afresh()); // 0
}
static int afresh(){
int xie=0;
try{
return xie; // 0
}finally{
xie=2;
System.out.println("finally "+xie); //finally 2
}
}
}
1. 明明在finally中修改了xie的值,为什么return回去的还是0,而在finally中删除的xie却是2?
很多人会去debug,但是这里debug的结果会和你预计有偏差:
2.明明debug都显示xie值更改为2了,为什么计算afresh()时依旧为0?
对于基本数据类来说,他的值传递很好理解,直接把数字拷贝一份赋值,在执行try语句块的return语句的时候,其实他的return语句执行了一半,可以理解为后半段执行了,将xie赋值给了return语句,但是前半段的return结束方法还没有执行,相当于数据库MVCC时的一个快照,将当前执行到这一步的xie变量的值生成一个快照保存下来给return副本,然后执行finally里面,xie变量的值确实变为2了,输出也是finally 2,但是finally执行完之后,会继续执行没有执行完的return前半段,此时,注意了,他返回的前面那个快照中的值,而不是后面经过finally修改的值,所以返回为0.
3.如果我们在finally中return一下又会是怎么样呢?
public class test {
public static void main(String[] args){
System.out.println(afresh());
}
static int afresh(){
int xie=0;
try{
return xie;
}finally{
xie=2;
System.out.println("finally "+xie);
return xie;
}
}
}
很明显,此时结果就是2了,因为try执行return的后半段保存快照后,就去执行finally里语句去了,finally遇到return直接就结束了,不会在让try语句再去执行return返回快照
4.上面的都是对于基本数据类型来说的,那么对于引用数据类型来说又是怎样呢?
我们先了解一下Java的传递方式:
在Java中,虽然不管是对于基本数据类型还是引用数据类型来说都是值传递,但是两者的值传递是有区别的,基本数据类型是直接传的字变量的值,拷贝了一份,而引用数据类型是把一个对象的地址拷贝了一份传递,很多人觉得(比如一个User,我把他传递给别人,但是别人修改了User里面的name,我这边的name也会改变)引用数据类型是引用传递,这是不对的,对于传递对象来说,举一个例子:
你有一把钥匙,当你的朋友想要去你家的时候,如果你直接把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如他在钥匙上刻下了自己名字,那么这把钥匙还给你的时候,你自己的钥匙上也会多出他刻的名字。
你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。
但是,不管上面哪种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。那你说你会不会受到影响?而我们在pass方法中,改变user对象的name属性的值的时候,不就是在“砸电视”么。你改变的不是那把钥匙,而是钥匙打开的房子。
所以在判断传递为引用对象时,应该判定的是该引用对象的地址是否改变,而不是其里面的内容。
修改代码:
public class test {
static class User{
String name;
int age;
public void setName(String name){
this.name=name;
}
}
public static void main(String[] args){
System.out.println(afresh().name);
}
static User afresh(){
User user = new User();
user.setName("侨");
try{
user.setName("侨1");
return user;
}finally{
user.setName("侨2");
System.out.println("finally "+user.name);
}
}
}
很明显,对于引用数据类型来说,finally里面修改数据,在try里面返回,依旧会改变,基于上面的解释,在try语句里面我们生成的是user的快照,他是一个地址值,我们也没有改变他,在finally里面我们只是改变他的一个属性值,所以返回拿到的是改变后的值。
注意点:
public class test {
static class User{
String name;
int age;
public void setAge(int age){
this.age=age;
}
}
public static void main(String[] args){
System.out.println(afresh().age);
}
static User afresh(){
User user = new User();
user.setAge(0);
try{
user.setAge(1);
return user;
}finally{
user.setAge(2);
System.out.println("finally "+user.age);
}
}
}
//对于age来说这样返回User的话也是一样的,但是我们看看下面的代码,不是返回User,而是返回User.age
public class test {
static class User{
String name;
int age;
public void setAge(int age){
this.age=age;
}
}
public static void main(String[] args){
System.out.println(afresh());
}
static int afresh(){
User user = new User();
user.setAge(0);
try{
user.setAge(1);
return user.age;
}finally{
user.setAge(2);
System.out.println("finally "+user.age);
}
}
}
//结果:
finally 2
1
//此时返回值是int类型,这时候和基本数据类型是等同的