Java基础知识

Test.main() 函数执行后的输出是()

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

 

 

首先,super()函数指的是调用父类的构造方法

new B()

执行B的构造函数,第一行是super(5);

此时执行的是A的构造函数,A的构造函数调用的是setValue()方法,由于B重写了A的这个方法,

所以!!!执行的是B的 setValue()方法。

即传入的参数是2*5=10

此时,因为super,所以调用的是父类的 setValue()方法,即value=10

第一行执行完毕。

第二行是 setValue(getValue()-3);

B没有getValue()方法,故执行父类的此方法,

try返回的是value=10+1=11,保存在临时栈中

finally中调用this的方法,这个this指的是B的对象,又重写,故就是B的 setValue()方法

value=2*11=22,第一个打印到屏幕上的数字

接下来参数 getValue()-3=11-3=8

传入B的 setValue()方法

此时value=2*8=16

至此,new B()执行结束

new B(). getValue()

B没有 getValue(),故执行A的 getValue()

try返回16+1=17,保存到临时栈中

finally调用B的 setValue()方法

value=17*2=34,第二个打印到屏幕上面的数字

最后主函数打印返回值,也就是try保存到临时栈的17

 


 

 

这题有两个考点:

  1. 动态分派 在调用new B()时调用A的构造器时和super.getValue()时的setValue(int value)方法是根据隐式对象的实际类型来确定的。只有实际类型未重写该方法时,才按照继承层次由下往上查找。这个可以参阅《深入理解JVM》的“分派”一节。
  2. finally块中的代码具体执行逻辑。这个可以通过javap查看字节码进行理解。详细可以参阅《深入理解JVM》和《JLS8》(JAVA虚拟机规范8)。
    Code:
       stack=3, locals=3, args_size=1
          0: aload_0             //将this引用入栈
          1: dup                 //复制栈顶元素
          2: getfield      #3    //消耗一个this引用,获取其value字段,入栈
          5: iconst_1            //int常量1入栈
          6: iadd                //将栈顶两元素相加(将消耗掉)并入栈
          7: putfield      #3    //取出栈顶元素存入value字段中
         10: aload_0             //将this引用入栈
         11: getfield      #3    //消耗一个this引用,获取其value字段,入栈
         14: istore_1            //取出value值存入局部变量表中(位置0为this引用)
         15: aload_0             //将this引用入栈
         16: aload_0             //将this引用入栈
         17: getfield      #3    //消耗一个this引用,获取其value字段,入栈
         20: invokevirtual #2    //调用实例方法setValue(消耗掉value和this引用)
         23: getstatic     #4    //获取System.out静态域,入栈
         26: aload_0             //将this引用入栈
         27: getfield      #3    //消耗一个this引用,获取其value字段,入栈
         30: invokevirtual #5    //调用实例方法println(消耗掉value和System.out引用)
         33: iload_1             //将局部变量表中第14步存入的value值取出,入栈
         34: ireturn             //返回栈顶的数据
     ...
    以字节码的角度看,最后返回的是前面已经保存在局部变量表中的value值。以代码的角度来看,finally块中的代码一定会执行,但前面return语句已经求得了value这个表达式的值,这个值不会因为finally块中value的改变而改变。当然,最好还是以字节码的角度去理解返回值为什么是前面求得的value值而不是在finally块中更新后的value值。

 



主要一点就是从头到尾都是子类对象在调用所有方法,所以除非显示写super,不然使用的方法都应该为子类重写过后的。所以第一个就应该(5*2+1)*2等于22。且注意,除非finally块中再写return,否则之前的return变量的值会被缓存,再修改变量不会改变return的值。

 其实关键问题在于try中的return值是在Try模块内的程序运行完之后就会保存下来,Finally模块中的程序不会影响到return的返回值,所以才会导致第一次输出的是22,但是return返回的却是11.


 

1、学习,关于函数调用谁的问题,正在执行的父类的构造函数,则在构造函数里面调用父类的函数

2、如果现在正在执行子类的构造函数,则构造函数里面调用的是子类的函数

3、this指正,最开始这个方法从哪个类发起,则this指正就是指向的最开始的那个对象

 

 

1.子类继承父类,调用方法时(如果没有显式声明super,则默认是this)先是调用子类中的方法,如果没有就调用父类中的方法。即以下几种情况:

         super.a()   ——调用父类的a方法

         this.a()      ——调用本类的a方法,如果本类没有该方法,应该会报错

         a()            ——相当于默认this,但是会先调用本类的方法,如果没有再去找父类中的方法来调用,如果父类找不到,则编译报错

***原题中的方法调用都是在B类中进行,所以B就是this,A就是super。

2.还有一点就是try{ }、catch{ }、finally{ }返回值的问题。

    try{ }中返回了某一个值,如果finally也有return,则finally中的返回值会覆盖try的返回值;如果finally没有返回值,则return try{}中缓存的返回值。


 

这题需要注意

1、除非调用super.setValue()否则都是调用子类的setValue(),

2、调用getValue()返回的值是value++后的值(已经存入returnValue, 等待finally块执行完成后返回给上一级)

3、finally块会修改value的值,最终的成员变量value值是finally块运算结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那些年的代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值