2022-07-22 17:15阅读: 40评论: 0推荐: 0

记一道代码分析题

来自极米的暑期服务端实习生笔试卷

/**
* @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);
}
}
}

执行分析:

  1. 主函数执行,压栈去new一个B对象
  2. 调用B的构造函数,B的构造函数里面有构造了一个A对象是什么意思?

啊啊啊啊——protect可以被子类访问,default不能,又记混了

那么此时B继承了A的value值=5,

此时是B对象在执行,此时value值为10

  1. 调用A构造,A又调用setValue()函数,但是根据上面的倒推,这里实际调用的是被重写的B的setValue()函数,B的setValue()函数又去调A的setValue()函数,最终把value变成了10

这里到底有没有A对象实例被创建?

  1. setValue()函数又去调getValue()函数

  2. getValue()函数首先把value++=11,然后在return前去执行了finally代码块

  3. finally代码块中this仍然是B对象实例,调用B自己的setValue()函数,value值被加倍=22,这里是第一个输出

  4. getValue()方法退出,返回22-3=19作为参数传给B的setValue方法,value=38,这里返回值是11?!,-3setValue获得的参数为8,结果是加倍value=16,B对象实例创建完成

那么也就是说:这里的return在finally之前就执行了

  1. 又调getValue()方法,value++=17,在setValue()方法被调用后加倍,输出34,这里是第二个输出

  2. 但是返回值仍然是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块的语句在trycatch中的return语句执行之后返回之前执行,且finally里的修改语句可能影响也可能不影响trycatchreturn已经确定的返回值,若finally里也有return语句则覆盖trycatch中return语句直接返回。

本文作者:YaosGHC

本文链接:https://www.cnblogs.com/yaocy/p/16506441.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(40)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起