• Java基础知识


    今天在牛客网刷题时碰到了这样一道题,感觉是很基础的知识点,但是要做出来并不容易,先来看一下题目

    [java] view plain copy
     
    1. /** 
    2.  * Created by zmt on 2016/12/22. 
    3.  */  
    4. public class Test {  
    5.     public static void main(String [] args){  
    6.         System.out.println(new B().getValue());  
    7.     }  
    8.     static class A{  
    9.         protected int value;  
    10.         public A(int v) {  
    11.             setValue(v);  
    12.         }  
    13.         public void setValue(int value){  
    14.             this.value = value;  
    15.         }  
    16.         public int getValue(){  
    17.             try{  
    18.                 value++;  
    19.                 return value;  
    20.             } catch(Exception e){  
    21.                 System.out.println(e.toString());  
    22.             } finally {  
    23.                 this.setValue(value);  
    24.                 System.out.println(value);  
    25.             }  
    26.             return value;  
    27.         }  
    28.     }  
    29.     static class B extends A{  
    30.         public B() {  
    31.             super(5);  
    32.             setValue(getValue() - 3);  
    33.         }  
    34.         public void setValue(int value){  
    35.             super.setValue(2 * value);  
    36.         }  
    37.     }  
    38. }  

    写出上述代码执行完成后的输出结果,这道题考的就是代码执行顺序的知识,如果大家不是很清楚,最直接的方法就是单步调试一下,这样就清楚了,我在每个方法上打上断点,开始调试看下执行过程。

    首先是main方法,new了一个B对象,然后就是调用该对象的getValue()方法,这个没什么好说的。

    接下来就要执行B类的构造方法了,这个也没啥说的

    然后执行B的构造方法,super(5);也就是调用B的父类A的构造方法,应该是到A构造的setValue()方法,同时A的成员变量value的值被赋为5,通过调试可以清楚的看到。

    接下来就是执行setValue()方法了,但是此时A类和B类都有一个setValue()方法,到底执行哪一个呢,我一开始认为是A类的setValue()方法,但是结果并不是这样的,看下调试过程。

    执行的是B的setValue()方法,,,因为现在正在执行B类的构造方法,所以默认先会调用B类中的方法,如果B类中没有,才会调用其父类A中的方法。我们继续看,,,接下来到super.setValue(2 * value),即执行A类的setValue()方法,这时,A类的成员变量value应该就变成了10

    继续往下看,这时B类的构造方法中的super(5)就执行完了,然后就到了setValue(getValue() - 3)方法

    接着执行getValue()方法,首先在B类中找,但B类没有getValue()方法,所以就执行A类中的getValue()方法,A类中肯定是有的,要不然编译就不会通过

    然后就开始执行try、catch、finally这一块,给A的成员变量value自增,从之前的10变为11,然后直接返回value,没有捕获异常,继续到finally里面的this.setValue(value)

    然后这个this指的到底是A类还是B类呢,答案是B类,因为现在是在执行B的构造方法,所以this指的应该是B类,即调用B类的setValue(int value)方法

    然后又super.setValue(2 * value);执行父类A的setValue(int value),把2 * 11作为参数传递,A类的setValue(int value)把传进来的value值赋给了A的成员变量value,变成了22。

    然后this.setValue(value)就执行完了,最后输出value,22

    到这儿getValue()方法就执行完了,但是有一点需要注意,此时的value为22,但是getValue()的返回值确是11,因为在try{ }中已经return了,所以这个方法的返回值级已经保存下来了,是11,即使finally{ }里面又对value的值做出了改变,但是getValue()的返回值是不会变的。接着继续执行B类构造方法中的setValue(getValue() - 3);getValue()是11,所以B的setValue(int value)方法的参数就为8,接着又到了super.setValue(2 * value)

    调用A类的setValue(int value)方法,同时将参数赋值给A类的成员变量value,此时value变为16

    到这儿B类的构造方法就全部执行完了,也就是new B(),然后又调用了该对象 的getValue()方法,B类没有,但是父类A有,所以,

    继续try{ }、catch{ }、finally{ },A类的成员变量value为16,然后value++,再返回,这时getValue()的返回值已经确定了,就是17,即使在finally中对value做出改变,其返回值不会变。然后到finally{ },又是this.setValue(value),前面已经说过了,这个this指的是B类的this,所以调用B类的setValue(int value)

    接着又是super.setValue(2 * value),调用A类的setValue(),并把2 * 17作为参数传递过去

    把参数赋给A的成员变量value,这时this.setValue(value)就执行完了,此时的value为34。最后输出value。

    需要注意的是,此时的getValue()方法的返回值是17,这个前面已经提到了,到这儿,整个new B().getValue()就执行完了,最后又输出了getValue的返回值,也就是17。所以整个过程执行完后的输出结果是22、34、17。。。。。。

    这道题虽然饶了很多弯,但是我们做完后发现整体过程其实并不是很复杂,就是自类继承父类,调用方法时先是调用子类中的方法,如果没有就调用父类中的方法,还有一点就是try{ }、catch{ }、finally{ }返回值的问题,一旦try{ }中返回了某一个值,如果finally有返回值,finally中的返回值会覆盖try的返回值,如果finally没有返回值,就是try中的返回值。掌握了这些,这道题就显得很简单了。

    原题链接:https://www.nowcoder.com/questionTerminal/af8cf04602e045958d13d16d20a1bf02

    文章摘要:https://blog.csdn.net/zhumintao/article/details/53818972

    中国男儿当自强不息,厚德载物。
  • 相关阅读:
    java操作redis之jedis篇
    实现指定步长循环后移字符串数组算法
    【PAT Advanced Level】1006. Sign In and Sign Out (25)
    银行计算利息
    中国人、美国人、北京人
    网络子系统55_ip协议分片重组_加入ipq
    C#拦截系统消息的方法-Application.AddMessageFilter
    C#实现在Form上截取消息的两种方法
    Geek改变世界
    中国黑客传说:游走在黑暗中的精灵
  • 原文地址:https://www.cnblogs.com/zhznb/p/9201045.html
Copyright © 2020-2023  润新知