Java 初始化执行顺序以及成员变量初始化顺序

Wesley13
• 阅读 613

一、静态变量初始化顺序

大家先看两个例子:

(1)

Java 初始化执行顺序以及成员变量初始化顺序 Java 初始化执行顺序以及成员变量初始化顺序

 1 public class SingleTon {
 2     public static int count1;
 3     public static int count2 = 1;
 4     private static SingleTon singleTon = new SingleTon();
 5     
 6     private SingleTon() {
 7         count1++;
 8         count2++;
 9     }
10 
11     public static SingleTon getInstance() {
12         return singleTon;
13     }
14 }
15 
16 class Test {
17     public static void main(String[] args) {
18         SingleTon singleTon = SingleTon.getInstance();
19         System.out.println("count1=" + singleTon.count1);
20         System.out.println("count2=" + singleTon.count2);
21     }
22 }

View Code

输出

count1=1
count2=2

(2)

Java 初始化执行顺序以及成员变量初始化顺序 Java 初始化执行顺序以及成员变量初始化顺序

 1 public class SingleTon {
 2 
 3     private static SingleTon singleTon = new SingleTon(); //(1)这一步初始化后,count1=1,count2=1
 4     public static int count1; //(2)这一步只是定义了count1变量,并未进行count1初始化,因此count1 =1 count2=1
 5     public static int count2 = 3;//(3)这一步 进行count2初始化,因此将原来的值覆盖,因此count2=3,count1 =1
 6 
 7     private SingleTon() {
 8         count1++; // 此时,count1还未被初始化,因此初始值为0,++后值为1
 9         count2++; // 此时,count2还未被初始化,因此初始值为0,++后值为1
10     }
11 
12     public static SingleTon getInstance() {
13         return singleTon;
14     }
15 }
16 
17 class Test {
18     public static void main(String[] args) {
19         SingleTon singleTon = SingleTon.getInstance();
20         System.out.println("count1=" + singleTon.count1);
21         System.out.println("count2=" + singleTon.count2);
22     }
23 }

View Code

count1=1

count2=3

在调用类静态成员(不管是方法还是变量)的时候,按顺序初始化静态属性和代码块,之后才会调用静态方法,非静态成员变量因为没有初始化类,故不会初始化。

二、继承中的初始化

看两个例子:

(1)

Java 初始化执行顺序以及成员变量初始化顺序 Java 初始化执行顺序以及成员变量初始化顺序

 1 class Meal {
 2     Meal() {
 3         System.out.println("Meal()");
 4     }
 5 }
 6 
 7 class Bread {
 8     Bread() {
 9         System.out.println("Bread()");
10     }
11 }
12 
13 class Cheese {
14     Cheese() {
15         System.out.println("Cheese()");
16     }
17 }
18 
19 class Lettuce {
20     Lettuce() {
21         System.out.println("Letuce()");
22     }
23 }
24 
25 class Lunch extends Meal {
26     Lunch() {
27         System.out.println("Lunch()");
28     }
29 }
30 
31 class PortabLunch extends Lunch {
32     PortabLunch() {
33         System.out.println("PortabLunch");
34     }
35 }
36 
37 public class Main extends  PortabLunch{
38     Bread bread = new Bread();
39     Cheese cheese = new Cheese();
40     Lettuce lettuce = new Lettuce();
41 
42     Main() {
43         System.out.println("Main");
44     }
45 
46     public static void main(String[] args) {
47         new Main();
48     }
49 }

View Code

输出:

Meal()
Lunch()
PortabLunch
Bread()
Cheese()
Letuce()
Main

说明:子类初始化前要(0)在其他任何事情发生之前,将分配给对象的存储空间初始化为二进制零(1)寻找父类构造器,并且步骤会不断递归,直到找到根类为止。然后自顶向下,逐层调用构造函数,直到最底层的父类构造器。(2)然后按照代码编译顺序依次初始化各成员变量 (3)最后调用本类的构造函数进行初始化。

(2)

Java 初始化执行顺序以及成员变量初始化顺序 Java 初始化执行顺序以及成员变量初始化顺序

 1 public class Glyph {
 2     void draw() {
 3         System.out.println("Glphy draw()");
 4     }
 5 
 6     Glyph() {
 7         System.out.println("Glphy() before draw");
 8         draw();//当子类调用父类构造器的时候,父类其实尚未初始化,因此调用的是子类的draw方法
 9         System.out.println("Glphy() after draw");
10     }
11 }
12 
13 class RoundGlyph extends Glyph {
14     private int radius = 1;
15 
16     RoundGlyph(int r) {
17         radius = r;
18         System.out.println("RoundGlyph.RoundGlyph(),radius:" + radius);
19     }
20 
21     void draw() {
22         System.out.println("RoundGlyph.draw(),radius:" + radius);
23     }
24 }
25 
26 class PolyConstruct {
27     public static void main(String[] args) {
28         new RoundGlyph(5);
29     }
30 }

View Code

输出

Glphy() before draw
RoundGlyph.draw(),radius:0
Glphy() after draw
RoundGlyph.RoundGlyph(),radius

说明:在调用父类构造器时,因为draw方法被子类_RoundGlyph覆写,因此在Glyph中调用的是子类的draw方法,并且此时由于radius还未进行初始化,因此其值是默认的初始值0._

(3)

Java 初始化执行顺序以及成员变量初始化顺序 Java 初始化执行顺序以及成员变量初始化顺序

 1 public class Glyph {
 2     void draw() {
 3         System.out.println("Glphy draw()");
 4     }
 5 
 6     Glyph() {
 7         System.out.println("Glphy() before draw");
 8         draw();//当子类调用父类构造器的时候,父类其实尚未初始化,因此调用的是子类的draw方法
 9         System.out.println("Glphy() after draw");
10     }
11 }
12 
13 class RoundGlyph extends Glyph {
14     private int radius = 1;
15 
16     RoundGlyph(int r) {
17         radius = r;
18         System.out.println("RoundGlyph.RoundGlyph(),radius:" + radius);
19     }
20 
21 //    void draw() {
22 //        System.out.println("RoundGlyph.draw(),radius:" + radius);
23 //    }
24 }
25 
26 class PolyConstruct {
27     public static void main(String[] args) {
28         new RoundGlyph(5);
29     }
30 }

View Code

输出:

Glphy() before draw
Glphy draw()
Glphy() after draw
RoundGlyph.RoundGlyph(),radius:5

 说明:本例子中,子类_RoundGlyph中不包含draw方法,因此也就不存在覆写的问题。所以父类初始化时调用的是本类中的draw方法。_

通过例子(2)(3)说明,在编写构造器时需要遵循一条准则:"用尽可能简单的方法使得对象进入正常状态;如果可以的话,尽量避免调用其他的方法"。在构造器内能够被唯一安全调用的方法是基类中的final方法(或者是private方法,因为它自动属于final方法),这些方法不能被覆盖,因此也不会 出项一些奇怪的问题_。_

下面附一张,JAVA成员变量初始化思维导图,对于理解这一块的知识很有帮助

 Java 初始化执行顺序以及成员变量初始化顺序

详细可参考这一文章:https://blog.csdn.net/fly_grass_fish/article/details/81116348   java静态变量static初始化顺序

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
2年前
java常用类(2)
三、时间处理相关类Date类:计算机世界把1970年1月1号定为基准时间,每个度量单位是毫秒(1秒的千分之一),用long类型的变量表示时间。Date分配Date对象并初始化对象,以表示自从标准基准时间(称为“历元”(epoch),即1970年1月1日08:00:00GMT)以来的指定毫秒数。示例:packagecn.tanjian
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Lua基础(对象)
:和.区别.   stu{id100,name"Tom",age21}成员变量   function stu.toString()成员函数    return stu.id .. stu.name .. stu.age   endprint(stu
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这