【小家java】类中静态代码块、构造代码块、静态变量执行顺序和继承逻辑

1、概述

诚如各位所知,java的三大特性:封装、继承、多态。其中继承,是java中最有学问的一点也是最相对来说最难理解的一些东西,本文针对于此,做一些实例分析,希望能够帮助大家理解java中的继承机制

2、栗子

情况一:当父类和子类有同名同类型的属性时,使用时需要注意

public class Main {
    public static void main(String[] args) {
        Parent chidParent = new Child();
        System.out.println("Parent:" + chidParent.getAge()); //40
        System.out.println("Parent:" + chidParent.age); //18 这个结果你能接受吗?哈哈
        Child child = Child.class.cast(chidParent);
        System.out.println("Child:" + child.getAge()); //40
        System.out.println("Child:" + child.age); //40
    }
}

@Getter
@Setter
class Child extends Parent {
    Integer age = 40; //名称和父类的同名
}

@Getter
@Setter
class Parent {
    Integer age = 18;
}

我们发现,那个18为什么会输出出来呢?父类和子类的变量是同时存在的,即使是同名。子类中看到的是子类的变量,父类中看到的是父类中的变量,它们互相隐藏,而同名的方法则是实实在在的覆盖(重写),属性不存在重写哟。有了这个解释,就好理解了吧
情况二:当父类和子类有同名不同类型的属性时,使用时需要注意

public class Main {
    public static void main(String[] args) {
        // 报错Error:(20, 12) java: com.sayabc.boot2demo1.main.Child中的getAge()
        // 无法覆盖com.sayabc.boot2demo1.main.Parent中的getAge()
        // 返回类型java.lang.String与java.lang.Integer不兼容
        Parent chidParent = new Child();
    }
}

@Getter
class Child extends Parent {
    String age = "40"; //名称和父类的同名

    public void setAge(String age) {
        this.age = age;
    }
}

@Getter
class Parent {
    Integer age = 18;

    public void setAge(Integer age) {
        this.age = age;
    }
}

我们高兴的发现,如果类型不同,编译器还发现不了,但是一运行,就报错啦。这算编译器的bug吗?哈哈
情况三:继承中最基本的类加载顺序,不做过多解释。静态代码块只执行一次,并且优先于mai方法先执行

public class Main {
    public static void main(String[] args) {
        Parent chidParent = new Child();
    }
}

@Getter
class Child extends Parent {

    static {
        System.out.println("Child的静态块");
    }

    {
        System.out.println("Child的构造块");
    }

    Child() {
        System.out.println("Child的构造方法");
    }
}

@Getter
class Parent {
    Integer age = 18;

    static {
        System.out.println("Parent的静态块");
    }

    {
        System.out.println("Parent的构造块");
    }

    Parent() {
        System.out.println("Parent的构造方法");
    }
}

结果如下:

Parent的静态块
Child的静态块
Parent的构造块
Parent的构造方法
Child的构造块
Child的构造方法

备注:此处需要注意,此处子类没有显示调用super(),但父类的构造还是执行了的。但是,但是,但是,如果构造快为有参构造,请记得显示调用super方法,否则父类是不能被初始化的。如果子类的构造器没有显示地调用超类的构造器,则将自动调用超类默认(没有参数) 的构造器。如果超类没有不带参数的构造器,并且在子类的构造器又没有显式地调用超类的其他构造器,则 java 编译器将报告错误

情况四:子类和父类有同名同类型的静态常量的时候

public class Main {
    public static void main(String[] args) {
        Parent parent = new Child();
        System.out.println(parent.name); //fangshixiangParent
        Child child = new Child();
        System.out.println(child.name); //fangshixiangChild
    }
}

@Getter
@Setter
class Child extends Parent {
    static String name = "fangshixiangChild";
}

@Getter
@Setter
class Parent {
    static String name = "fangshixiangParent";
}

有了前面的基础,这个现象就很好解释了。同理:当有同名不同类型的属性时,直接获取属性还是会各自获取到自己的,但get方法就不行,就会报错了。

3、使用场景

各种设计模式,都会以此为依托,才能有更好的设计

4、最后

java的三大特性都非常的重要,如果不理解虚拟机对类的一些处理,有时候会犯迷糊,影响逻辑的设计,所以此文用简单用例希望能帮助大家理解。日后也许会持续更新

—-题后语—-

有任何问题,可以跟我留言讨论,欢迎指正,不胜感激。
有任何疑问,亦可扫码向我提我哟~

猜你喜欢

转载自blog.csdn.net/f641385712/article/details/80350192