Java中类的初始化块问题(二)
来源:互联网 发布:mysql导出表结构 编辑:程序博客网 时间:2024/06/10 19:18
声明:本博客为原创博客,未经允许,不得转载!小伙伴们如果是在别的地方看到的话,建议还是来csdn上看吧(原文链接地址为http://blog.csdn.net/bettarwang/article/details/26141167),毕竟在csdn上看代码和提问、讨论都更方便。
在Java中类的初始化块问题(一)一文中,我已经阐述过Java中的静态初始化块、非静态初始化块及构造函数的执行顺序问题,但是那篇文章中没有涉及类的继承中初始化块的执行顺序,本文将重点探讨。
为了能减少读者看代码的时间,本文将采用Java中类的初始化块问题(一)中Base作为基类(只是略有改动),从而代码如下:
import java.util.*;class Base{ private String name="Tom"; private int age=48; { System.out.println("name="+name+" age="+String.valueOf(age)); } static { System.out.println("static initial block in Base"); } public Base() { System.out.println("Base Constructor"); }}public class Sub extends Base{ private String hobby="Soccer"; { System.out.println("hobby is "+hobby); } static { System.out.println("static initial block in Sub"); } public Sub() { System.out.println("Sub Constructor"); } public static void main(String[]args) { Sub s; //s=new Sub(); }}
此时输出结果如下图所示:
图1 未新建子类对象时的输出结果
显然,此时由于只有基类和子类被加载到内存,但是并未创建对象,因而此时只有基类和子类的静态初始化块被执行。
如果将上面代码中的s=new Sub();的注释符去掉,则此时输出结果如下图所示:
图2 新建子类对象时的输出结果
显然,此时执行顺序为:基类的静态初始化块--子类的静态初始化块--基类的非静态初始化块--基类的构造函数--子类的非静态初始化块--子类的构造函数。
但是为什么是这样的执行顺序呢?因为首先类被加载到内存,因而先输出基类和子类的静态初始化块,然后由于要生成子类对象,因而非静态初始化块也被执行。从而执行基类的非静态初始化块之后再执行其构造函数。同理,在子类的构造函数被执行之前要先执行其非静态初始化块。
其实这里涉及到类的初始化问题。一个类要被使用,需要经过装载、连接和初始化过程(这里所谓的“初始化”与上面不同,其实是狭义的初始化,特指非静态成员的初始化)。下面是这三个过程的含义。
装载:类装载器把编译形成的class文件载入内存,创建类相关的Class对象,它里面封装了相应类的类型信息;
连接:连接又可分为三个阶段,即验证、准备和解析。验证就是要确保数据格式的正确性,并适合JVM使用;准备即JVM为静态变量分配内存空间,并设置默认值;解析过程就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把其替换成直接引用。
从而,对于一个类来说,如果不生成该类的对象,那么只会在连接中的准备阶段执行其静态成员(包括静态变量和静态初始化块)。注意这个过程与是否生成对象无关,所以即使是下面这段代码,也会有相应的输出。
import java.util.*;class Base{ private String name="Tom"; private int age=48; { System.out.println("name="+name+" age="+String.valueOf(age)); } static { System.out.println("static initial block in Base"); } public Base() { System.out.println("Base Constructor"); }}public class Sub extends Base{ private String hobby="Soccer"; { System.out.println("hobby is "+hobby); } static { System.out.println("static initial block in Sub"); } public Sub() { System.out.println("Sub Constructor"); } public static void main(String[]args) { }}此时输出结果如下图所示:
图3 main函数体为空时的输出结果
显然,虽然此时main函数为空,但是由于类在准备阶段会执行静态成员,因而会有上面的输出。
如果需要生成实例化的对象,那么除了上面两个阶段,还要经过非静态成员的初始化过程(其顺序为非静态成员在类中出现的顺序)。至此,我们就可以完美解释图2中的输出了。
- Java中类的初始化块问题(二)
- Java中类的初始化块问题(一)
- Java中类的静态初始化块
- Java中初始化块和静态初始化块的区别
- 有关于在Java 类的静态初始化块中创建一个自身实例的问题。
- java中初始化块
- java中初始化块
- Java中初始化块的真实作用
- Java的初始化块
- java的初始化块
- Java的初始化块
- Java类初始化顺序问题:静态初始化块,非静态初始化块以及构造函数
- java类中静态域、块,非静态域、块,构造函数的初始化顺序(回钦波)
- java类中静态域、块,非静态域、块,构造函数的初始化顺序(回钦波)
- java类中静态域、块,非静态域、块,构造函数的初始化顺序
- Java类的初始化 静态代码块
- java类的初始化,static块初始
- Java类的初始化块总结
- 单片机直流电机驱动电路
- 2014年百度之星程序设计大赛 Energy Conversion
- leetcode? Single Number II
- ubuntu下终端提示符设置
- static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较
- Java中类的初始化块问题(二)
- 二进制转十进制--字符串转换成整形变量---位操作----编程随笔(5)
- getMeasuredHeight(),getScrollY(),getHeight()的区别和联系
- 相同的生命周期
- Android程序启动初始画面的实现
- 关于c语言的输入函数问题
- 杭电1225 Football Score (结构体排序)
- 排序算法之希尔排序
- zlib编译