Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序
来源:互联网 发布:中国新闻自由 知乎 编辑:程序博客网 时间:2024/05/24 11:13
1 public class Baset { 2 private String baseName = "base"; 3 // 构造方法 4 public Baset() { 5 callName(); 6 } 7 // 成员方法 8 public void callName() { 9 // TODO Auto-generated method stub10 System.out.println("basename:" + baseName);11 }12 //静态内部类13 static class Sub extends Baset {//static必须写在开头14 // 静态字段15 private String baseName = "sub";16 public Sub() {17 callName();18 }19 // 重写父类的方法20 public void callName() {21 System.out.println("subname:" + baseName);22 }23 }24 25 public static void main(String[] args) {26 Baset base = new Sub();27 }28 }
求这段程序的输出。
解答此题关键在于理解和掌握类的加载过程以及子类继承父类后,重写方法的调用问题:
一、从程序的执行顺序去解答:
1.编译;当这个类被编译通知后,会在相应的目录下生成两个.class 文件。一个是 Base.class,另外一个就是Base$Sub.class。这个时候类加载器将这两个.class 文件加载到内存
2、Base base= new Sub():
声明父类变量base对子类的引用,JAVA类加载器将Base,Sub类加载到JVM(Java虚拟机);
3、JVM为Base,Sub 的的成员开辟内存空间
此时,Base 和Sub类中的值为null;
4、new Sub();
这个时候会调用Sub类的隐式构造方法,
Sub的构造方法本质为:
public Sub(){
super();// 调用父类的构造方法。必须在构造方法中的第一行,为什么呢?这是因为在一些程序的升级中,要兼容旧版本的一些功能,父类即原先的一些初始化信息也要保证 //被执行到,然后执行当前
baseName = "sub";//子类字段初始化
}
new Sub()执行到super()这行代码也就是跑到父类中去执行了,我们跳转到父类中的无参构造方法中执行,最后执行Sub()中的baseName = "sub"
5、public Base() ;
父类无参构造方法的本质为:
public Base(){
baseName= "base";//父类字段初始化
callName();
}
即将父类的baseName赋值为“base”,赋值后调用callName();
6、callName()方法在子类中被重写,因此调用子类的callName(),子类的callName方法执行,打印输出的是子类的baseName 字段的值,而这个时候子类的构造函数中字段的赋值还未执行。
7、父类的构造函数执行完毕,这个时候又回到子类当中,从super()的下一行继续执行,这个时候才为子类字段baseName 分配好存储空间,随后为其赋值:
可见,在baseName = "sub"执行前,子类的callName()已经执行,所以子类的baseName为默认值状态null;
二、另写两个程序,进行更具体的分析
1、第一个程序:
1 public class InitialOrderTest { 2 // 变量 3 public String field = "变量"; 4 // 静态变量 5 public static String staticField="静态变量"; 6 //父类静态方法 7 public static void Order(){ 8 System.out.print("父类静态方法"); 9 System.out.println("staticField:"+staticField);10 }11 12 // 静态初始代码块13 static{14 System.out.println("静态初始化块");15 System.out.println("staticField:"+staticField);16 }17 // 初始化代码块 18 {19 System.out.println("初始化代码块");20 System.out.println("field:"+field);21 }22 // 构造函数23 public InitialOrderTest(){24 System.out.println("构造器");25 26 }27 28 public static void main(String[] args) {29 System.out.println("-----[[-------");30 System.out.println(InitialOrderTest.staticField);31 InitialOrderTest.Order();32 System.out.println("------]]------");33 InitialOrderTest i = new InitialOrderTest();34 System.out.println("-----[[-------");35 System.out.println(InitialOrderTest.staticField);36 InitialOrderTest.Order();37 System.out.println("------]]------");38 39 }40 }
执行结果为:
第一个程序总结:
1)、java中的块分为静态块(static{})和非静态块({}),这两种的执行是有区别的:
非静态块的执行时间是:在执行构造函数之前。 静态块的执行时间是:class文件加载时执行。
static类型的属性也是在类加载时执行的。
2)、可见Java类的实例变量初始化的过程:
static类型的成员属性执行,静态块(static{})按顺序执行,然后非静态成员变量初始化,非静态代码块({})执行,最后执行构造方法。
static类型与static块按先后顺序执行。
---------------------------------------------------------------------------------------------------------------------------------------------------
2、第二个程序:
1 public class BaseTest { 2 // 父类变量 3 private String baseName = "base"; 4 // 父类静态变量 5 private static String staticField = "父类静态变量"; 6 // 父类静态方法 7 public static void Order() { 8 System.out.println("父类静态方法-"); 9 System.out.println("staticField:" + staticField);10 }11 // 父类静态初始代码块12 static {13 System.out.println("父类静态初始化代码块-");14 System.out.println("staticField:" + staticField);15 }16 // 初始化代码块17 {18 System.out.println("父类非静态初始化代码块-");19 System.out.println("baseName:" + baseName);20 }21 // 构造函数22 public BaseTest() {23 System.out.println("父类构造方法");24 callName();25 }26 // 成员方法27 public void callName() {28 System.out.println("父类callName方法-");29 System.out.println("baseName:" + baseName);30 }31 32 // 静态内部类33 static class Sub extends BaseTest {34 // 子类变量35 private String baseName = "sub";36 // 子类 静态变量37 private static String staticField = "子类静态变量";38 39 // 子类静态方法40 public static void Order() {41 System.out.println("子类静态方法-");42 System.out.println("staticField:" + staticField);43 }44 45 // 子类静态初始化代码块46 static {47 System.out.println("子类静态初始化代码块-");48 System.out.println("staticField:" + staticField);49 }50 // 子类非静态初始化代码块51 {52 System.out.println("子类非静态初始化代码块-");53 System.out.println("baseName:" + baseName);54 }55 56 public Sub() {57 System.out.println("子类构造方法");58 callName();59 }60 61 public void callName() {62 System.out.println("子类重写父类callName方法-");63 System.out.println("baseName:" + baseName);64 }65 }66 67 public static void main(String[] args) {68 69 BaseTest b = new Sub();70 71 System.out.println("-----[[-------");72 Sub.Order();73 System.out.println(Sub.staticField);74 System.out.println(BaseTest.staticField);75 BaseTest.Order();76 System.out.println("------]]------");77 78 }79 }
执行结果:
第二个程序总结:
1)、可见Java初始化的顺序:
1 1 父类静态变量初始化 2 2 父类静态代码块-static{ } 3 3 子类静态变量初始化 4 4 子类静态代码块-static{ } 5 5 父类非静态变量初始化 6 6 父类非静态代码块-{} 7 7 父类构造方法 8 8 子类非静态变量初始化 9 9 子类非静态代码块-{}10 10 子类构造方法
- Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序
- java类中静态域、块,非静态域、块,构造函数的初始化顺序(回钦波)
- java类中静态域、块,非静态域、块,构造函数的初始化顺序(回钦波)
- java类中静态域、块,非静态域、块,构造函数的初始化顺序
- java类静态域、块,非静态域、块,构造函数的初始化顺序
- java类静态域、块,非静态域、块,构造函数的初始化顺序
- java类静态域、块,非静态域、块,构造函数的初始化顺序
- java类静态域、块,非静态域、块,构造函数的初始化顺序
- Java类静态属性、静态块、非静态属性、非静态块、构造函数在初始化时的执行顺序
- Java类静态属性、静态块、非静态属性、非静态块、构造函数在初始化时的执行顺序
- Java类静态属性、静态块、非静态属性、非静态块、构造函数在初始化时的执行顺序
- Java中静态变量、块、非静态变量、块和构造器的初始化顺序
- Java类的初始化顺序 (静态变量、静态初始化块、变量、初始化块、构造方法)
- Java类的初始化顺序 (静态变量、静态初始化块、变量、初始化块、构造器
- Java类的初始化顺序 (静态变量、静态初始化块、变量、初始化块、构造器)
- Java中静态代码块、非静态代码块以及构造函数的初始化顺序
- java 中类初始化,构造方法,静态成员变量,静态块的加载顺序
- JAVA中父类与子类静态代码块、非静态代码块、构造函数的加载顺序
- eclipse乱码解决方法
- Android View和ViewGroup
- eclipse 快捷键
- QScrollBar定制背景色
- sql中视图的作用
- Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序
- 反射——Java高级开发必备知识
- MyEclipse 启动 tomcate 失败 解决方法
- Bootloader
- 你不知道的JavaScript--Item13 理解 prototype, getPrototypeOf 和__proto__
- 语音识别资料
- 【bzoj2243】 [SDOI2011]染色 树链剖分+线段树
- 排序算法之冒泡排序
- MD设计之ToolBar