详解java初始化顺序

初始化

构造器初始化

自动初始化会在构造器调用之前发生

如:

public class Counter{
    int i;
    Counter(){
        i=7;
	}
}

那么,i会被先初始化为0,然后在构造函数中赋值为7。对于所有的基本类型和对象引用,包括在定义时已经指定初值的变量,这种情况的成立的;因此,编译器不会强制你一定要在构造器的某个地方或在使用他们之前对元素进行初始化—因为初始化早已得到了保证。但是局部变量不会被初始化,java的措施是如果你使用了一个未初始化的变量,那么将会报错

初始化顺序

在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散步在方法定义之间,它仍旧会在任何方法(包括构造器)被调用之前得到初始化。例如:

package practice;

class window{
	public window(int index) {
		// TODO Auto-generated constructor stub
		System.out.println("window"+index);
	}
}

class House{
	window w1=new window(1);     //--------1
	public House() {
		// TODO Auto-generated constructor stub
		System.out.println("House");  //---4
		w3=new window(33);       //--------5
		
	}
	window w2=new window(2);     //--------2
	void f() {
		System.out.println("f()"); //------6
	}
	window w3=new window(3);    //---------3
}

public class InitialSort {
	
	public static void main(String args[]) {
		House house=new House();
		house.f();
	}

}

output:
window1
window2
window3
House
window33
f()

静态初始化

package practice;

import javax.naming.event.NamingExceptionEvent;

class Bowl{
	public Bowl(int mark) {
		// TODO Auto-generated constructor stub
		System.out.println("Bowl"+mark);
	}
	public void f1(int mark) {
		System.out.println("f1("+mark+")");
	}
	
}

class Table {
	static Bowl bowl1=new Bowl(1);
	public Table() {
		// TODO Auto-generated constructor stub
		System.out.println("Table()");
		bowl1.f1(1);
	}
	static Bowl bowl2=new Bowl(2);
}


public class StaticInitialSort {
	static Table table=new Table();
	public static void main(String args[]) {
		System.out.println("run main");
	}
}

output:
Bowl1
Bowl2
Table()
f1(1)
run main

初始化的顺序是先静态对象,再非静态对象。

分析输出结果,因为这段代码要执行main()函数,所有必须要先加载StaticInitialSort类,这时其静态域table就会被初始化,导致Table类也会被加载进来,同理,Table类中的静态域对应的类Bowl也会被加载进来。因此,在这个特殊的程序中,所有的类都会在main()方法执行前被加载到JVM中来,也就有了输出结果中所显示的数据。

总结一下对象的创建过程,假设由一个名为Dog的类:

  1. 即使没有显式地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类的对象或者使用类的静态成员、方法时,JVM需要加载Dog类的class文件。
  2. 载入Dog.class文件后(实际上是创建了一个Class对象),有关静态初始化的所有动作都会执行,因此,静态初始化只在Class对象首次加载的时候执行一次。
  3. 当使用new Dog()创建对象时,首先会在堆上为Dog分配足够的内存空间。
  4. 这块存储空间会被清零,这就自动地将Dog对象中地所有基本类型成员变量初始化为默认值,而引用则置为NULL。
  5. 执行所有出现于字段定义处地初始化动作。
  6. 执行构造器。

实例初始化

package practice;

class Test{
	{
		System.out.println("实例");
	}
	public Test() {
		// TODO Auto-generated constructor stub
		System.out.println("call constructor");
	}
}
public class 实例 {
	public static void main(String args[]) {
		Test Test1=new Test();
		Test Test2=new Test();
	}

}


实例
call constructor
实例
call constructor

实例代码块和静态代码块地区别就是就是少了一个static,因此每new 一个对象都会执行实例代码块,而静态代码块是在JVM加载class的时候执行的,只执行一次。

实例代码块在匿名内部内中的初始化时是必须的,因为它没法用构造函数初始化。

数组的初始化

基本类型数组的初始化

编译器不允许指定数组的大小,当定义一个数组

int a[];

此时拥有的只是这个数组的一个引用(你已经为这个应用分配了足够的存储空间),但是没有给数组对象本身分配任何空间。

给数组对象分配空间有两种方式:

  1. 在创建数组的时候分配:

    int a[]={1,2,3,4,5};

  2. 使用初始化表达式

    int a[]=new int[];

非基本类型的数组

如果你创建了一个非基本类型数组,那么你创建的是一个引用数组。以Integer为例子:

public class ArrayTest{
    public static void main(String agrs[])
    {
		Integer a[]=new Integer[500];
        for(int i=0;i<a.lenght;i++)
        {
            a[i]=Math.Random()*1000;
        }
        System.out.println(a.toArray());
    }
}

在这里,不像基本类型数组一样,即便使用new创建数组之后,

Integer a[]=new Integer[500];

它也还是一个引用数组,并且直到创建新的Integer对象,并把对象赋值个引用后,初始化过程才算结束:

a[i]=Math.Random()*1000;

还要其他的两种初始化非基本类型数组的方式:

Integer a[]={new Integer[10],new Integer[20],3};
Integer a[]=new Integer[]{new Integer[10],new Integer[20],3};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值