记一道代码分析题
来自极米的暑期服务端实习生笔试卷
/**
* @author yao 2022/7/22
* 输出是:22、34、17
*/
public class Test {
public static void main(String[] args) {
System.out.println(new B().getValue());
}
static class A {
protected int value;
public A(int v) {
setValue(v);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
try {
value++;
return value;
} finally {
this.setValue(value);
System.out.println(value);
}
}
}
static class B extends A {
public B() {
super(5);
setValue(getValue() - 3);
}
public void setValue(int value) {
super.setValue(2 * value);
}
}
}
执行分析:
- 主函数执行,压栈去new一个B对象
- 调用B的构造函数,B的构造函数里面有构造了一个A对象是什么意思?
啊啊啊啊——protect可以被子类访问,default不能,又记混了
那么此时B继承了A的value值=5,
此时是B对象在执行,此时value值为10
- 调用A构造,A又调用
setValue()
函数,但是根据上面的倒推,这里实际调用的是被重写的B的setValue()
函数,B的setValue()
函数又去调A的setValue()
函数,最终把value变成了10
这里到底有没有A对象实例被创建?
-
setValue()
函数又去调getValue()
函数 -
getValue()
函数首先把value++
=11,然后在return
前去执行了finally代码块 -
finally代码块中this仍然是B对象实例,调用B自己的
setValue()
函数,value值被加倍=22,这里是第一个输出 -
getValue()
方法退出,返回22-3=19作为参数传给B的这里返回值是11?!,-3setValue
方法,value=38,setValue
获得的参数为8,结果是加倍value=16,B对象实例创建完成
那么也就是说:这里的return在finally之前就执行了
-
又调
getValue()
方法,value++
=17,在setValue()
方法被调用后加倍,输出34,这里是第二个输出 -
但是返回值仍然是17,这里是main方法中的输出,至此执行完毕
后记
疯狂挖坑
- 坑1:protect修饰,子类可访问,default不能
- 坑2:子类构造函数中必须通过
super()
显示调用父类构造函数,必须是第一句,这一句中仍然是B对象在执行 - 坑3:
return语句在finally代码块之前执行
回头
上面第三点应该不对,finally代码块应该是在return语句前执行的
public static void main(String[] args) {
tempTest t = new tempTest();
System.out.println(t.doSome());
}
public String doSome(){
try{
System.out.println("try代码块中代码执行");
return "返回";
}finally {
System.out.println("finally代码块中代码执行");
}
}
这边的输出是:
try代码块中代码执行
finally代码块中代码执行
返回
可以看出,确实是在finally代码块执行完后才return的
那么为什么会出现上面代码中的情况呢?
public class FinallyTest {
public int method(){
int x = 1;
try{
++x;
return x;
}finally {
x+=5;
}
}
public static void main(String[] args) {
FinallyTest test = new FinallyTest();
System.out.println(test.method());
}
}
这段代码输出是2
网上有这么一句话
大意就是如果在try中return的情况下,先把try中将要return的值先存到一个本地变量中,即本例中的x=2将会被保存下来。接下来去执行finally语句,最后返回的是存在本地变量中的值,即返回x=2.
还有一点要注意的,如果你在finally里也用了return语句,比如return ++x。那么程序返回值会是3。因为规范规定了,当try和finally里都有return时,会忽略try的return,而使用finally的return。
总结
finally
块的语句在try
或catch
中的return
语句执行之后返回之前执行,且finally
里的修改语句可能影响也可能不影响try
或catch
中return
已经确定的返回值,若finally
里也有return
语句则覆盖try
或catch中
的return
语句直接返回。