记一道代码分析题
来自极米的暑期服务端实习生笔试卷
/** * @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
语句直接返回。
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16506441.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步