java关于继承和多态的思考

1:类初始化的顺序(废话不多说,直接看demo)

父类

	/**
     * 父类
     */
    static class Father {
        /**
         * 姓名
         */
        public String name = initName();

        /**
         * 年龄
         */
        public static int age = initAge();

        /**
         * 初始化姓名
         *
         * @return 姓名
         */
        private String initName() {
            System.out.println(++order + " father init name");
            return "father";
        }

        /**
         * 初始化年龄
         *
         * @return 年龄
         */
        private static int initAge() {
            System.out.println(++order + " father init static age");
            return 50;
        }

        // 构造代码块
        {
            System.out.println(++order + " father constructor code block");
        }

        // 静态代码块
        static {
            System.out.println(++order + " father static code block");
        }

        /**
         * 构造方法
         */
        public Father() {
            System.out.println(++order + " father constructor getName = " + getName());
        }

        /**
         * 获取姓名
         *
         * @return 姓名
         */
        public String getName() {
            return name;
        }
    }

子类

	/**
     * 子类
     */
    static class Son extends Father {
        /**
         * 姓名
         */
        public String name = initName();

        /**
         * 年龄
         */
        public static int age = initAge();

        /**
         * 初始化姓名
         *
         * @return 姓名
         */
        private String initName() {
            System.out.println(++order + " son init name");
            return "son";
        }

        /**
         * 初始化年龄
         *
         * @return 年龄
         */
        private static int initAge() {
            System.out.println(++order + " son init static age");
            return 20;
        }

        // 构造代码块
        {
            System.out.println(++order + " son constructor code block");
        }

        // 静态代码块
        static {
            System.out.println(++order + " son static code block");
        }

        /**
         * 构造方法
         */
        public Son() {
            System.out.println(++order + " son constructor getName = " + getName());
        }

        /**
         * 获取姓名
         *
         * @return 姓名
         */
        @Override
        public String getName() {
            return name;
        }
    }

执行函数

	/**
     * 顺序
     */
    private static int order = 0;

    public static void main(String[] args) {
        Father son = new Son();
    }

父类和子类的代码基本一致,执行函数就只是创建一个子类。这段代码主要是探究类初始化过程中,构造方法,普通变量,静态变量,构造代码块和静态代码块的加载顺序,大家可以想想输出的结果是什么,下面我们来看结果

在这里插入图片描述
通过输出结果,可以得到结论

1:加载父类的静态变量和静态代码块(谁在前面先加载谁)
2:加载子类的静态变量和静态代码块(谁在前面先加载谁)
3:加载父类的普通变量和构造代码块(谁在前面先加载谁)
4:加载父类的构造方法
5:加载子类的普通变量和构造代码块(谁在前面先加载谁)
6:加载子类的构造方法

输出结果有一点比较有意思的是第6行,父类构造方法调用getName方法,输出结果为null,这里就涉及到多态了,因为getName方法调用到的其实是子类getName,但是这个时候子类的name变量还没被加载,所以为null

再看一个demo

	/**
     * 父类
     */
    static class Father {
        /**
         * 姓名
         */
        public static String name = "father";

        // 静态代码块
        static {
            System.out.println("father init");
        }
    }

    /**
     * 子类1
     */
    static class Son extends Father {
        // 静态代码块
        static {
            System.out.println("son init");
        }
    }


    public static void main(String[] args) {
        System.out.println("Son1.name = " + Son.name);
    }

输出:子类静态代码块竟然没有执行,是不是很诡异,这个是因为子类没有静态变量name,实际调用的是父类的静态变量,所以初始化的的时候,实际上就只是初始化父类

在这里插入图片描述

为了印证上面的说法,直接修改demo,给子类也添加一个静态变量name

 /**
     * 父类
     */
    static class Father {
        /**
         * 姓名
         */
        public static String name = "father";

        // 静态代码块
        static {
            System.out.println("father init");
        }
    }

    /**
     * 子类1
     */
    static class Son extends Father {
        /**
         * 姓名
         */
        public static String name = "son";

        // 静态代码块
        static {
            System.out.println("son init");
        }
    }


    public static void main(String[] args) {
        System.out.println("Son1.name = " + Son.name);
    }

输出:可以看到这个时候子类的静态方法被执行了

在这里插入图片描述

2:多态的执行(废话不多说,直接看demo)

	/**
     * 父类
     */
    static class Father {
        /**
         * 姓名
         */
        public String name = "father";

        /**
         * 打印姓名1
         */
        public void printName1() {
            System.out.println("name = " + name);
        }

        /**
         * 打印姓名2
         */
        public void printName2() {
            System.out.println("name = " + getName());
        }

        /**
         * 获取姓名
         *
         * @return 姓名
         */
        public String getName() {
            return name;
        }
    }

    /**
     * 子类1
     */
    static class Son1 extends Father {
        /**
         * 姓名
         */
        public String name = "son1";

        /**
         * 打印姓名1
         */
        @Override
        public void printName1() {
            System.out.println("name = " + name);
        }

        /**
         * 打印姓名2
         */
        @Override
        public void printName2() {
            System.out.println("name = " + getName());
        }

        /**
         * 获取姓名
         *
         * @return 姓名
         */
        @Override
        public String getName() {
            return name;
        }
    }

    /**
     * 子类2
     */
    static class Son2 extends Father {
        /**
         * 姓名
         */
        public String name = "son2";

        /**
         * 获取姓名
         *
         * @return 姓名
         */
        @Override
        public String getName() {
            return name;
        }
    }

    public static void main(String[] args) {
        Father son1 = new Son1();
        son1.printName1();
        son1.printName2();

        System.out.println("-------------");

        Father son2 = new Son2();
        son2.printName1();
        son2.printName2();
    }

输出:编译看左边,运行看右边,所以实际执行都是子类的方法,其中son1重写了printName1和printName2,所以执行的都是重写的方法。son2没有对printName1和printName2进行重写,这个时候printName1调用的是父类方法,printName2调用的是父类方法打印getName方法的结果,但是因为子类有重写getName,所以打印的其实是子类getName的返回结果

在这里插入图片描述

再看一个demo

	/**
     * 父类
     */
    static class Father {

        /**
         * 打印姓名
         *
         * @param obj 参数
         */
        public void printName(Object obj) {
            System.out.println("father printName obj " + obj);
        }

        /**
         * 打印姓名
         *
         * @param str 参数
         */
        private void printName(String str) {
            System.out.println("father printName str " + str);
        }
    }

    /**
     * 子类
     */
    static class Son extends Father {

        /**
         * 打印姓名
         *
         * @param obj 参数
         */
        @Override
        public void printName(Object obj) {
            System.out.println("son printName obj " + obj);
        }
    }


    public static void main(String[] args) {
        Father son = new Son();
        son.printName("爸爸");

        System.out.println("-----------");

        new Son().printName("儿子");
    }

输出:第一个printName调用的是父类的私有方法,该方法是重载方法,结果说明运行看右边,只针对子类可以继承到的方法

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值