静态代码块、静态变量,构造代码块、实例变量的执行顺序和继承逻辑(下)

简介: 静态代码块、静态变量,构造代码块、实例变量的执行顺序和继承逻辑(下)

case4:子类和父类有同名同类型的静态变量的时候



结论就不用解释了:静态变量属于类的,和继承无关。


case5:静态代码块属于类的,并且优先于main方法执行(有难度)



public class StaticDemo1 {
    public static void main(String[] args) {
        speak();
        //StaticDemo1 t1 = new StaticDemo1();
        //System.out.println(t1.i);
    }
    // 静态变量
    static int i = 1;
    // 静态方法
    static void speak() {
        System.out.println("a");
    }
    // 静态代码块
    static {
        i = i + 3;
        System.out.println(i);
    }
    // 构造函数
    public StaticDemo1() {
        i = i + 5;
        System.out.println(i);
    }
}


输出:


4
a


4在a之前输出,证明:毕竟mian方法属于StaticDemo1类的方法,所以会先执行此类的静态变量 + 静态代码块。


其它不变,改为这样:


public static void main(String[] args) {
    StaticDemo1 t1 = new StaticDemo1();
    System.out.println(t1.i);
    speak();
}
4
9
9
a
  1. 执行静态代码块:打印4


  1. 执行构造方法:打印9


  1. System.out.println(t1.i)直接输出,打印9(此时i的值是9)


  1. 执行speak():打印1


public static void main(String[] args) {
    speak();
    StaticDemo1 t1 = new StaticDemo1();
    System.out.println(t1.i);
}
4
a
9
9


这个输出,在意料之中,不再解释喽。


这是一道面试题,考察的是:static块真正的执行时机。若想真正了解类的装载,请去了解JVM吧~


注解对执行顺序的影响



特别的,这里我介绍一下各种注解影响的执行顺序,如下代码:


@Component  
public class InitBeanTest implements InitializingBean,ApplicationListener<ContextRefreshedEvent> {  
    @Autowired
    DemoService demoService;  
    public InitBeanTest() {     
       System.err.println("----> InitSequenceBean: constructor: "+demoService);     
    }  
    @PostConstruct  
    public void postConstruct() {  
        System.err.println("----> InitSequenceBean: @PostConstruct: "+demoService);  
    }  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        System.err.println("----> InitSequenceBean: afterPropertiesSet: "+demoService);  
    }  
    @Override  
    public void onApplicationEvent(ContextRefreshedEvent arg0) {  
        System.err.println("----> InitSequenceBean: onApplicationEvent");  
    }  
}  
执行结果:
----> InitSequenceBean: constructor: null
----> InitSequenceBean: @PostConstruct: com.xxx.service.impl.DemoServiceImpl@40fe544
----> InitSequenceBean: afterPropertiesSet: com.xxx.service.impl.DemoServiceImpl@40fe544
----> InitSequenceBean: onApplicationEvent


根据代码演示,得出文字版结论:


  构造函数是每个类最先执行的,这个时候,bean属性还没有被注入


  @PostConstruct优先于afterPropertiesSet执行:在这执行,属性已经完成了赋值(注入)


继续补充:子类默认调用父类构造函数问题


Java有个很有趣的现象:父类有N多个构造函数,子类如果只写一个的话那么子类最终就只有一个构造函数可用,因此子类在这方面要特别的注意喽。


默认情况下,子类在使用构造函数初始化时(不管是子类使用有参构造还是无参构造),默认情况下都会调用父类的无参构造函数(相当于调用了super())。看看下面几个变种如下:


// 父类木有空的构造  只有一个有参构造
class Parent{
    private Integer id;
    public Parent(Integer id){
        System.out.println("this is parent cons...");
    }
}


此时候我们发现发现如下三问题:


1、子类Child必须有对应的有参构造


image.png


2、super(id)必须显示的写出,否则编译不通过

image.png


3、原则上,子类的构造函数不能多于父类的


image.png


4、子类构造函数若多余父类(或者类型啥的和父类不匹配),需要显示的调用父类构造函数


image.png


结论:


1、子类构造器执行之前必须能够先执行父类的构造函数(super(xxx)必须放在第一行代码)


2、若父类有空构造,子类构造默认都会调用super()。若父类木有空构造,子类所有构造都必须显示调用super(xxx)·


总结


据反馈,看了此篇文章后,很多小伙伴感觉自己学的是另外一个Java,其实这就是JavaSE,很多架构师认为,Java基础才是精华中的精华(一流),Spring才属于应用级别的技术(二流)。


相关文章
|
存储 Cloud Native Linux
C++ 继承下的构造函数和析构函数执行顺序
C++ 继承下的构造函数和析构函数执行顺序
实例详解局部代码块,构造代码块,静态代码块
实例详解局部代码块,构造代码块,静态代码块
|
XML Java 数据格式
Java中静态代码块、构造方法、代码块、父类与子类之间执行顺序及父类子类实例化对象
Java中静态代码块、构造方法、代码块、父类与子类之间执行顺序及父类子类实例化对象
159 0
|
Java
类成员(代码块)
类成员(代码块)
56 1
Java中类的初始化过程:(静态成员变量,静态代码块,普通成员变量,代码块初始化顺序)
Java中类的初始化过程:(静态成员变量,静态代码块,普通成员变量,代码块初始化顺序)
131 0
Zp
父类静态代码块、非静态代码块、构造方法、子类静态代码块、子类非静态代码块、子类构造方法执行顺序
父类静态代码块、非静态代码块、构造方法、子类静态代码块、子类非静态代码块、子类构造方法执行顺序
Zp
70 0
|
Java
构造方法,静态代码块,成员变量的加载顺序
构造方法,静态代码块,成员变量的加载顺序
142 0
|
Java 编译器 Spring
静态代码块、静态变量,构造代码块、实例变量的执行顺序和继承逻辑(上)
静态代码块、静态变量,构造代码块、实例变量的执行顺序和继承逻辑(上)
类、变量、块、构造器、继承初始化顺序,终极解答。
最近发现微信群里面有些群友在讨论类的初始化顺序,如类的静态变量、成员变量、静态代码块、非静态代码块、构造器,及继承父类时,它们的初始化顺序都是怎样的,下面我通过例子来说明这个情况,以免被人误导。
类、变量、块、构造器、继承初始化顺序,终极解答。
|
Java
Java代码块(静态和非静态)在子父类中的执行顺序
Java代码块(静态和非静态)在子父类中的执行顺序
151 0