JAVA变量初始化顺序

变量概要

在Java程序中,变量可分为成员变量和局部变量。成员变量是指定义在类体内的变量,它们存储在类的栈中。如果定义该成员变量时没有使用static修饰,该成员变量又被称为非静态变量或实例变量,否则就被称为静态变量或类变量。局部变量可分为3类:
  • 形参:在方法签名中定义的局部变量,由方法调用者为其赋值,随方法的结束而消亡;
  • 方法内的局部变量:必须在方法内对其进行显示初始化,从初始化完成后开始生效,随方法的结束而消亡;
  • 代码块内的局部变量:必须在代码块内对其进行显示初始化,从初始化完成后开始生效,随代码块的结束而消亡。
由上可知,局部变量是指在方法签名、方法内和代码块内定义的变量,它们被存储在方法的栈内存中。

类变量属于该类本身,而实例变量属于该类的实例。在同一个JVM内,每个类只对应一个Class对象,但每个类可以创建多个Java对象。
由于同一个JVM内每个类只对应一个Class对象,因此用一个JVM内的一个类的类变量只需一块内存空间;但对于实例变量而言,该类每创建一次实例,就需要为实例变量分配一块内存空间。也就是说程序中有几个实例,实例变量就需要几块内存空间。


成员变量初始化顺序

Java虚拟机每次创建对象都会为实例变量分配内存空间,并对实例变量执行初始化。在代码中,程序可以在3个地方对实例变量执行初始化:
1、定义实例变量时指定初始值;
2、非静态初始化块中对实例变量指定初始值;
3、构造器中对实例变量指定初始值。
其中前两种方式比最后一种方式更早执行,但前两种方式的执行顺序与它们在源程序中的排列顺序相同。

示例一:

package test;

/**
 * 输出结果:
block
constructor
name=Jimy
 * 
 * @author hbin(cn.binbin@qq.com)
 * @site http://blog.csdn.net/binbinxyz
 * @date 2014-5-29
 */
public class Person
{
	private String name = "Tom";
	
	{
		System.out.println("block");
		name = "Jack";
	}
	
	public Person()
	{
		System.out.println("constructor");
		name = "Jimy";
	}

	public static void main(String[] args)
	{
		System.out.println("name=" + new Person().name);
	}
}

示例二:

package test;

/**
 * 输出结果:
block
name=Jack
 * 
 * @author hbin(cn.binbin@qq.com)
 * @site http://blog.csdn.net/binbinxyz
 * @date 2014-5-29
 */
public class Person_1
{
	private String name = "Tom";
	
	{
		System.out.println("block");
		name = "Jack";
	}

	public static void main(String[] args)
	{
		System.out.println("name=" + new Person_1().name);
	}
}

示例三:

package test;

/**
 * 输出结果:
block
name=Tom
 * 
 * @author hbin(cn.binbin@qq.com)
 * @site http://blog.csdn.net/binbinxyz
 * @date 2014-5-29
 */
public class Person_2
{
	{
		System.out.println("block");
		name = "Jack";
	}

	private String name = "Tom";
	
	public static void main(String[] args)
	{
		System.out.println("name=" + new Person_2().name);
	}
}

示例一说明:实例变量的初始化方式1和2比方式3更早执行。

示例二和三对比说明:实例变量的初始化方式1和2的执行顺序与它们在源程序中的排列顺序相同。

静态变量初始化顺序

Java虚拟机对一个Java类只初始化一次,因此Java程序每运行一次,系统只为类变量分配一次内存空间,执行一次初始化。在代码中,程序可以在2个地方对类变量执行初始化:
1、定义类变量时指定初始值;
2、静态初始化块中对类变量指定初始值。
这两种方式的执行顺序与它们在源程序中的排列顺序相同。

示例四:

package test;

/**
 * 输出结果:
static block
id=2
 * 
 * @author hbin(cn.binbin@qq.com)
 * @site http://blog.csdn.net/binbinxyz
 * @date 2014-5-29
 */
public class Person_3
{
	private static int id = 1;
	static
	{
		System.out.println("static block");
		id = 2;
	}

	public static void main(String[] args)
	{
		System.out.println("id=" + Person_3.id);
	}
}
示例五:

package test;

/**
 * 输出结果:
static block
id=1
 * 
 * @author hbin(cn.binbin@qq.com)
 * @site http://blog.csdn.net/binbinxyz
 * @date 2014-5-29
 */
public class Person_4
{
	static
	{
		System.out.println("static block");
		id = 2;
	}
	private static int id = 1;

	public static void main(String[] args)
	{
		System.out.println("id=" + Person_4.id);
	}
}
示例四和五对比说明:静态变量的初始化方式1和2的执行顺序与它们在源程序中的排列顺序相同。

经典示例

package test;

public class Price
{
	private static Price INSTANCE = new Price(2);
	private static int INIT_PRICE = 20;
	private int currentPrice;
	
	public Price(int discount)
	{
		currentPrice = INIT_PRICE - discount;
	}
	
	public static void main(String[] args)
	{
		System.out.println(Price.INSTANCE.currentPrice);
		System.out.println(new Price(2).currentPrice);
	}
}


表面上看,程序输出两个Price的currentPrice都应该返回18(20-2),但实际上运行后输出结果为-2和18。如果仅仅停留在代码表面看,很难得到正确结果,下面从内存角度来分析这个程序。首先看类中的主函数main,执行System.out.println(Price.INSTANCE.currentPrice);时程序第一次用到Price类,这个时候会对Price类进行初始化,初始化过程为:
1、为Price的两个类变量(INSTANCE和INIT_PRICE)分配内存空间,此时INSTANCE、INIT_PRICE的值为默认值null和0;
2、按照初始化代码(定义时指定初始值和初始化块中执行初始值)的排列顺序对类变量执行初始化;
   a)对INSTANCE执行初始化:创建Price实例用到Price类的带参数构造器,执行其中的currentPrice=INIT_PRICE-discount。因为此时的INIT_PRICE=0,所以currentPrice=-2;
   b)对INIT_PRICE执行初始化:INIT_PRICE=20;
3、这个时候主函数main()中System.out.println(Price.INSTANCE.currentPrice);执行完毕,出书结果为-2;
4、之后执行new Price(2);这行代码,会先执行1、2、3过程,此时currentPrice=-2,INIT_PRICE=20。然后调用Price类的带参构造器执行currentPrice=INIT_PRICE– discount,得到 currentPrice=18。

参考博文

小武灵灵 http://www.2cto.com/kf/201305/211071.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值