Java初始化的例子分析
来源:互联网 发布:快速排序算法 图解 编辑:程序博客网 时间:2024/05/18 03:11
借用一个小例子来分析Java程序的初始化过程,其中涉及类的加载,初始化顺序
class Insect {private int i = 9;protected int j;Insect() {System.out.println("i = " + i + ", j = " + j);j = 39;}private static int x1 = printInt("static Insect.x1 initialized");static int printInt(String s) {System.out.print(s);System.out.println(". Insect.x1 = " + x1 );return 47;}}public class Beetle extends Insect {private int k = printInt("Beetle.k initialized");public Beetle() {System.out.println("k = " + k);System.out.println("j = " + j);}private static int x2 = printInt("static Beetle.x2 initialized");public static void main(String[] args) {System.out.println("Beetle constructor");Beetle b = new Beetle();}}
以下对程序的分析,如有错误,不吝指教。
(1)如果要运行这段程序,启动虚拟机时,指定要Beetle(包含main()方法)作为启动的类,虚拟机会先初始化Beetle类。
(2)当初始化一个类时,发现其父类尚未初始化,则需要先触发其父类的初始化,所以需要先初始化Insect(注意:这里的初始化指的是类加载过程中的初始化阶段,不是new 类的对象);
(3)在初始化的过程中,会对static的属性进行赋值,也就是Insect.x1。在类的加载过程中分为以下几个阶段:加载-->验证-->准备-->解析-->初始化。在准备阶段会对类变量(注意是类变量,static修饰的变量)进行内存分配,静态变量的初始值是零值。此时Insect.x1 = 0;
(4)现在Insect进行到了加载过程的初始化阶段,会对Insect.x1赋值,
x1 = printInt("static Inject.x1 initialized");
此时,Insect.x1 = 47。Insect类加载完毕
(5)加载Beetle类,同样是在准备阶段将Beetle.x2置零,初始化阶段对
Beetle.x2 = printInt("static Beetle.x2 initilaize");此时,Beetle.x2 = 47。Beetle类加载完毕。
(6)开始执行main()方法,第一条语句是打印;
(7)执行第二条语句,创建Beetle对象b。子类对象会包含一个父类的子对象,这个对象与你用父类直接创建的对象是一样的,区别就是一个被包装在子类的内部,一个在外部。所以首先会调用父类相应的构造方法,创建父类的对象,由于Beetle没有显式的调用父类的构造方法,虚拟机会使用父类的无参构造方法。
(8)这个时候相当于执行:new Insect()。会执行一下动作:
a .首先会在堆上分配一块内存;
b.然后这块存储空间会被置零,这就自动的将Insect类里面的所有属性变成零值(注意,Java要求:在调用任何方法之前,所有属性都至少有一个初值。正是通过置零存储空间来保证这条规则的)。由于x1是类变量,并不存储在这块在堆上分配内存,x1的值仍然为47,i=0,j=0;
c.执行所有出现字段定义处的初始化动作,也就是private int i=9。此时,x1=47,i=9;j=0;
d.执行构造函数;
创建父类对象完成,Insect.x1 = 47,i=9,j=39。
(9)创建子类Beetle的对象,如第八步一般,k的值被置零,k=0;接着执行k定义处的初始化,k=47;执行构造函数;
至此,程序运行完毕,程序的输出结果是:
/********
//验证第三步中所说,在准备阶段给x1赋零值。
static Insect.x1 initialized. Insect.x1 = 0
static Beetle.x2 initialized. Insect.x1 = 47
Beetle constructor
i = 9, j = 0
Beetle.k initialized. Insect.x1 = 47
k = 47
j = 39
********/
============================================================================================
看了上面的内容,觉得还不够完整,再补充一点关于静态语句块和静态变量、子类初始化的内容。
class Print {//为了演示静态语句块和静态属性的初始化是按照定义的先后顺序而设的public Print() {System.out.println("class Print is created.");}//为了演示构造子类之前,先调用父类的构造方法public Print(String className) {System.out.println("class Print is create by " + className);}}class Father {private Print p1 = new Print("Father");static {System.out.println("Before static field init." + "\n----------------" );//在类变量定义之前的静态语句块不可以使用,编译无法通过//System.out.println(p);//但是可以在静态语句块中对其进行赋值,这样是没问题的//p = new Print();//即使已经定义了,也不能使用//Cannot reference a field before it is defined//System.out.println(p);}static Print p = new Print();static {System.out.println("----------------\n" + "After static field init.");}public Father(int i) {System.out.println("class Father is created ");}}class Son extends Father {private Print p = new Print("Son");public Son() {//父类的构造方法要放在有效代码的第一行super(0);System.out.println("class Son is created");}public static void main(String[] args) {new Son();}}
/*output*/
Before static field init.----------------class Print is created.----------------After static field init.class Print is create by Fatherclass Father is created //以上两行的输出说明先调用父类的构造方法class Print is create by Sonclass Son is created
从上面的输出中,我们可以得到以下结论:
1)静态语句块和静态属性的初始化顺序是按照定义的先后顺序来进行的,但是都早于非静态属性的初始化(其实这是句废话,看了上面一段的就明白了)。在静态属性定义之前的静态语句块可以对其赋值,但是不能是使用(即使已经初始化了,仍然不能使用,记住:只有在定义处之后才能使用)。
2)我们知道,当子类继承父类时,子类已经知道了父类的一切,并且可以访问父类中任何声明为public和protected的成员。这意味着,必须假定父类的所有成员都是有效的。为了确保这一目的,唯一的办法就是:首先调用父类的构造器。在调用父类构造器之前,自然会执行父类属性定义处的初始化(又说了一句废话)。
3)关于构造方法:
a.一个类如果没有构造方法,编译器认为:这个类需要构造方法,给它提供一个默认无参构造方法,这个构造方法什么也不做;
b.这个类如果有了构造方法,无论有无参数,编译器都会认为:这个类有构造方法,它知道自己要做什么,所以不需要我操心了,不要给它提供任何额外的构造方法了。
关于子类构造方法:子类构造方法必须在第一行(不包括注释)使用关键字super调用父类的构造方法,否则编译器默认调用父类的无参构造方法。关于这句话的解释是这样的:如果父类有无参构造方法,无论是自己写的,还是编译器默认创建的,那么可以不不使用super(),当然也可以使用;如果父类没有无参构造方法,那就必须使用super(参数)来显式调用,否则编译无法通过。
以上内容均为原创,转载请注明:http://blog.csdn.net/yuhongye111/article/details/25502057
- Java初始化的例子分析
- java惰性初始化的小例子
- Java对象初始化过程例子分析(一)
- 举例分析Java对象的初始化过程
- Java静态变量的初始化分析
- 例子演示java继承初始化
- 初始化顺序(Thinking in Java中的一段有意思的例子)
- Java 父类子类的对象初始化过程及例子
- java构造方法、静态变量初始化顺序的小例子
- java分析html文档的例子
- java 多线程 例子分析
- 关于java构造器初始化顺序例子
- Java静态变量初始化的一个实例的分析
- Java常见错误与问题分析-对象的初始化
- Java类的加载和初始化顺序分析
- java------继承与初始化----一个程序的调试及分析
- Java类的加载和初始化顺序分析
- Java语言基础-数组的静态初始化和内存分析
- (int&)a和(int)a的区别
- 一致性hash算法 - consistent hashing
- spring组件扫描<context:component-scan/>使用详解
- C语言快速排序算法代码分析
- 先进先出队列(链表实现)
- Java初始化的例子分析
- SequenceInputStream类(对包含多个对象内的文件连续进行读取)
- java网络爬虫-总结
- hibernate4.2关于sessionFactory的一点变化
- 16/32位MD5加密工具类
- copy_to_user和copy_from_user
- JS实现随机显示一个数组中的数值;
- 大数据Lambda架构
- Android开发大牛们的博客地址