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

一、静态变量初始化顺序

大家先看两个例子:

(1)

1 1 public class SingleTon { 2 2 public static int count1; 3 3 public static int count2 = 1; 4 4 private static SingleTon singleTon = new SingleTon(); 5 5 6 6 private SingleTon() { 7 7 count1++; 8 8 count2++; 9 9 } 1010 1111 public static SingleTon getInstance() { 1212 return singleTon; 1313 } 1414 } 1515 1616 class Test { 1717 public static void main(String[] args) { 1818 SingleTon singleTon = SingleTon.getInstance(); 1919 System.out.println("count1=" + singleTon.count1); 2020 System.out.println("count2=" + singleTon.count2); 2121 } 2222 }

View Code

输出

count1=1
count2=2

(2)

1 1 public class SingleTon { 2 2 3 3 private static SingleTon singleTon = new SingleTon(); //(1)这一步初始化后,count1=1,count2=1 4 4 public static int count1; //(2)这一步只是定义了count1变量,并未进行count1初始化,因此count1 =1 count2=1 5 5 public static int count2 = 3;//(3)这一步 进行count2初始化,因此将原来的值覆盖,因此count2=3,count1 =1 6 6 7 7 private SingleTon() { 8 8 count1++; // 此时,count1还未被初始化,因此初始值为0,++后值为1 9 9 count2++; // 此时,count2还未被初始化,因此初始值为0,++后值为1 1010 } 1111 1212 public static SingleTon getInstance() { 1313 return singleTon; 1414 } 1515 } 1616 1717 class Test { 1818 public static void main(String[] args) { 1919 SingleTon singleTon = SingleTon.getInstance(); 2020 System.out.println("count1=" + singleTon.count1); 2121 System.out.println("count2=" + singleTon.count2); 2222 } 2323 }

View Code

count1=1

count2=3

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

二、继承中的初始化

看两个例子:

(1)

1 1 class Meal { 2 2 Meal() { 3 3 System.out.println("Meal()"); 4 4 } 5 5 } 6 6 7 7 class Bread { 8 8 Bread() { 9 9 System.out.println("Bread()"); 1010 } 1111 } 1212 1313 class Cheese { 1414 Cheese() { 1515 System.out.println("Cheese()"); 1616 } 1717 } 1818 1919 class Lettuce { 2020 Lettuce() { 2121 System.out.println("Letuce()"); 2222 } 2323 } 2424 2525 class Lunch extends Meal { 2626 Lunch() { 2727 System.out.println("Lunch()"); 2828 } 2929 } 3030 3131 class PortabLunch extends Lunch { 3232 PortabLunch() { 3333 System.out.println("PortabLunch"); 3434 } 3535 } 3636 3737 public class Main extends PortabLunch{ 3838 Bread bread = new Bread(); 3939 Cheese cheese = new Cheese(); 4040 Lettuce lettuce = new Lettuce(); 4141 4242 Main() { 4343 System.out.println("Main"); 4444 } 4545 4646 public static void main(String[] args) { 4747 new Main(); 4848 } 4949 }

View Code

输出:

1Meal() 2Lunch() 3PortabLunch 4Bread() 5Cheese() 6Letuce() 7Main

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

(2)

1 1 public class Glyph { 2 2 void draw() { 3 3 System.out.println("Glphy draw()"); 4 4 } 5 5 6 6 Glyph() { 7 7 System.out.println("Glphy() before draw"); 8 8 draw();//当子类调用父类构造器的时候,父类其实尚未初始化,因此调用的是子类的draw方法 9 9 System.out.println("Glphy() after draw"); 1010 } 1111 } 1212 1313 class RoundGlyph extends Glyph { 1414 private int radius = 1; 1515 1616 RoundGlyph(int r) { 1717 radius = r; 1818 System.out.println("RoundGlyph.RoundGlyph(),radius:" + radius); 1919 } 2020 2121 void draw() { 2222 System.out.println("RoundGlyph.draw(),radius:" + radius); 2323 } 2424 } 2525 2626 class PolyConstruct { 2727 public static void main(String[] args) { 2828 new RoundGlyph(5); 2929 } 3030 }

View Code

输出

1Glphy() before draw 2RoundGlyph.draw(),radius:0 3Glphy() after draw 4RoundGlyph.RoundGlyph(),radius

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

(3)

1 1 public class Glyph { 2 2 void draw() { 3 3 System.out.println("Glphy draw()"); 4 4 } 5 5 6 6 Glyph() { 7 7 System.out.println("Glphy() before draw"); 8 8 draw();//当子类调用父类构造器的时候,父类其实尚未初始化,因此调用的是子类的draw方法 9 9 System.out.println("Glphy() after draw"); 1010 } 1111 } 1212 1313 class RoundGlyph extends Glyph { 1414 private int radius = 1; 1515 1616 RoundGlyph(int r) { 1717 radius = r; 1818 System.out.println("RoundGlyph.RoundGlyph(),radius:" + radius); 1919 } 2020 2121 // void draw() { 2222 // System.out.println("RoundGlyph.draw(),radius:" + radius); 2323 // } 2424 } 2525 2626 class PolyConstruct { 2727 public static void main(String[] args) { 2828 new RoundGlyph(5); 2929 } 3030 }

View Code

输出:

1Glphy() before draw 2Glphy draw() 3Glphy() after draw 4RoundGlyph.RoundGlyph(),radius:5

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

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

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

 

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java常用类(2)

三、时间处理相关类Date类:计算机世界把1970年1月1号定为基准时间,每个度量单位是毫秒(1秒的千分之一),用long类型的变量表示时间。Date分配Date对象并初始化对象,以表示自从标准基准时间(称为“历元”(epoch),即1970年1月1日08:00:00GMT)以来的指定毫秒数。示例:packagecn.tanjian

Lua基础(对象)

:和.区别.   stu{id100,name"Tom",age21}成员变量   function stu.toString()成员函数    return stu.id .. stu.name .. stu.age   endprint(stu

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