本来就是刷一个题 结果给我整晕了特此记录一下
先说结论: java 多态指的是运行时多态和编译时多态,编译时的多态呢比较好理解就是
根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。
运行时多态:也叫作动态绑定,一般是指在执行期间(非编译期间)判断引用对象的实际类型,根据实际类型判断并调用相应的属性和方法。主要用于继承父类和实现接口时,父类引用指向子类对象。这个是jvm 有一套规范的 一般我们听到的是 若是字类复写了父类的方法则优先调用字类的方法,否则调用父类的方法, 但是这个调用这要时刻记住(即是this 当前指向誰)否则就是下面这个题目直接把你绕傻
本来的题目是这样的; 问最后打印的是三个啥值
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);
}
}
}
这里贴上我自己的理解 后面写晕了可能有不对的但是最底下有大神的解释可以自己去看,反正我是不想看了
package cn.source.utils;
/**
* @ClassName: aaa
* @Description: TODO
* @author: human
* @date: 2021-03-10 10:10
*/
public class aaa {
public static void main(String[] args) {
//程序的入口
// 1 执行这个 new B() 这个动作;
System.out.println(new B().getValue());
}
static class A {
protected int value;
//2 new B 之前 先执行A的构造方法
public A(int v) {
// 执行a 自己的setvalue
setValue(v);
}
// 5 第一次执行 set value 方法
//13 第二次执行 setvalue 方法
//20 第三次执行 setvalue 方法
public void setValue(int value) {
// 6 此时的value =2*5
// 14 此时的value= 11*2
//21 value = 2*8 16
this.value = value;
}
//8 第一次被调用用 此时value 等于10
//
// 第二次被调用 此时value 等于16
// 第三次被调用 此时的值是34
public int getValue() {
try {
//9 10+1 =11
value++;
// 10 return 的作用 保留当前的这个值11但是必须把finally块儿里边的代码走完 11
return value;
} finally {
//11
// 真的狗 this的作用誰调用我,我就是誰 此时this字类B对象,然后。setValue 方法
// 这个时候value 等于11 调用字类的方法 逻辑自己去看 这个时候设置的value 34 17
this.setValue(value);
//15 所以第一次在这个地方打印的就是22
// 所以在这个地方打印的就是34
// 最后一次调用打印的是17
System.out.println(value);
}
}
}
static class B extends A {
// 实例化b 对象执行改构造方法
public B() {
// 2
// 显示的写了调用父类的构造方法,
// 但是父类的构造方法里边是调用的setValue方法;
// 此时运行时多态因为字类重写了父类的这个setValue 所以调用的时自己的 setValue 方法
// 自己的setValue在内部还是调用的父类的setValue方法 通过super关键字显示的调用 只是参数变了 把这个值给了过去
super(5);
// 7
//这个时候显示的调用了自己的setValue方法,
//字类没有重写父类的getValue方法,运行时多态调用的是父类的getValue方法
// get value 方法执行完毕之后 return 会保留当前的值 所以此时(11-3)8
// 设置完毕之后value的值为16
//16 getvalue 返回值为11
//17 执行 11-3 =8
setValue(getValue() - 3);
}
// 3 执行自己的 set value 方法
//11 第二次执行自己的set value方法
// 18 第三次执行自己的setvalue 方法此时的值为8
public void setValue(int value) {
// 4 在内部还是调用的父类的方法 只是参数变了 此时传给父类的set value 方法的参数是2*5
//12 现在的值是 2* 11
//19 调用父类的构造方法 此时传入的值为 2*8
super.setValue(2 * value);
}
}
}
思考和解决这个题的主要核心在于对java多态的理解。个人理解时,执行对象实例化过程中遵循多态特性 ==> 调用的方法都是将要实例化的子类中的重写方法,只有明确调用了super.xxx关键词或者是子类中没有该方法时,才会去调用父类相同的同名方法。
Step 1: new B()构造一个B类的实例
此时super(5)语句调用显示调用父类A带参的构造函数,该构造函数调用setValue(v),这里有两个注意点一是虽然构造函数是A类的构造函数,但此刻正在初始化的对象是B的一个实例,因此这里调用的实际是B类的setValue方法,于是调用B类中的setValue方法 ==> 而B类中setValue方法显示调用父类的setValue方法,将B实例的value值设置为2 x 5 = 10。
紧接着,B类的构造函数还没执行完成,继续执行setValue(getValue()- 3) // 备注1语句。
先执行getValue方法,B类中没有重写getValue方法,因此调用父类A的getValue方法。这个方法比较复杂,需要分步说清楚:
调用getValue方法之前,B的成员变量value值为10。
value++ 执行后, B的成员变量value值为11,此时开始执行到return语句,将11这个值作为getValue方法的返回值返回出去
但是由于getValue块被try finally块包围,因此finally中的语句无论如何都将被执行,所以步骤2中11这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
这里有很重要的一点:finally语句块中 this.setValue(value)方法调用的是B类的setValue方法。为什么?因为此刻正在初始化的是B类的一个对象(运行时多态),就像最开始第一步提到的一样(而且这里用了使用了this关键词显式指明了调用当前对象的方法)。因此,此处会再次调用B类的setValue方法,同上,super.关键词显式调用A的setValue方法,将B的value值设置成为了2 * 11 = 22。
因此第一个打印项为22。
finally语句执行完毕 会把刚刚暂存起来的11 返回出去,也就是说这么经历了这么一长串的处理,getValue方法最终的返回值是11。
回到前面标注了 //备注1 的代码语句,其最终结果为setValue(11-3)=>setValue(8)
而大家肯定也知道,这里执行的setValue方法,将会是B的setValue方法。 之后B的value值再次变成了2*8 = 16;
Step2: new B().getValue()
B类中没有独有的getValue方法,此处调用A的getValue方法。同Step 1,
调用getValue方法之前,B的成员变量value值为16。
value++ 执行后, B的成员变量value值为17,此时执行到return语句,会将17这个值作为getValue方法的返回值返回出去
但是由于getValue块被try finally块包围而finally中的语句无论如何都一定会被执行,所以步骤2中17这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
finally语句块中继续和上面说的一样: this.setValue(value)方法调用的是B类的setValue()方法将B的value值设置成为了2 * 17 = 34。
因此第二个打印项为34。
finally语句执行完毕 会把刚刚暂存起来的17返回出去。
因此new B().getValue()最终的返回值是17.
Step3: main函数中的System.out.println
将刚刚返回的值打印出来,也就是第三个打印项:17
最终结果为 22 34 17。