本来就是刷一个题 结果给我整晕了特此记录一下

先说结论: 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。


版权声明:本文为metjoyful原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/metjoyful/article/details/114634152