java成员变量的初始化顺序

本文对比分析了Java和C#中静态成员的初始化顺序,详细解释了两种语言在实例化过程中的不同表现,并通过具体示例展示了初始化的具体流程。
1:java中静态成员的初始化顺序
public class TestClassInitialize {

	public static void main(String[] args) {
		
		System.out.println("第一次调用:");
		B b = new B();
		System.out.println("第二次调用:");
		b = new B();
	}
	
}

class A {
	
	private static int a = setA();
	private int a1 = setA1();
	
	static{
		System.out.println("--父类静态代码块");
	}
	
	private static int setA() {
		System.out.println("-父类静态变量……");
		return 0;
	}

	public int setA1() {
		System.out.println("---父类成员变量……非静态变量");
		return 0;
	}
	
	public A() {
		System.out.println("----父类构造函数");
	}
	
}

class B extends A {
	
	private static int b = setB();
	private int b1 = setB1();
	
	static{
		System.out.println("--子类静态代码块");
	}
	
	private static int setB() {
		System.out.println("-子类静态变量……");
		return 0;
	}

	public int setB1() {
		System.out.println("---子类成员变量……非静态变量");
		return 0;
	}
	
	public B() {
		System.out.println("----子类构造函数");
	}
}


结果:

第一次调用:
-父类静态变量……
--父类静态代码块
-子类静态变量……
--子类静态代码块
---父类成员变量……非静态变量
----父类构造函数
---子类成员变量……非静态变量
----子类构造函数
第二次调用:
---父类成员变量……非静态变量
----父类构造函数
---子类成员变量……非静态变量
----子类构造函数

由此可见:java中正常的实例化顺序是:父类实例化--》成员变量--》构造函数。加入静态类型之后会初始化所有的静态类型(包括子类和父类),然后才是正常的初始化:父类静态类型--》子类静态类型--》父类实例化--》成员变量--》构造函数。静态类型的初始化顺序都是先变量后程序块。

在C#中类中,静态成员有:静态变量、静态函数和静态构造函数,而在java中是没有静态构造函数的,取而代之的是静态代码块。静态成员一般放在静态区,而且是属于类的,所以我们不用实例化对象,直接调用静态函数,比如工具类的方法一般声明为静态函数。C#和java静态成员的初始化顺序是不一样的。

1.c#中静态成员的初始化顺序

class A
{
    static int a = setA();//静态变量
    int a1 = setA1();//非静态变量
 
    private static int setA1()
    {
        Console.WriteLine("父类非静态变量");
        return 1;
    }
 
    public static int setA()
    {
        Console.WriteLine("父类静态变量");
        return 1;
    }
 
    public A()//构造函数
    {
        Console.WriteLine("父类构造函数");
    }
 
    static A()//静态构造函数
    {
        Console.WriteLine("父类静态构造函数");
    }
}
 
class B : A
{
    static int b = setB();//静态变量
    int b1 = setB1();//非静态变量
 
    private static int setB1()
    {
        Console.WriteLine("子类非静态变量");
        return 1;
    }
 
    public static int setB()
    {
        Console.WriteLine("子类静态变量");
        return 1;
    }
 
    public B()//构造函数
    {
        Console.WriteLine("子类构造函数");
    }
 
    static B()//静态构造函数
    {
        Console.WriteLine("子类静态构造函数");
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("第一次调用。。。");
        B b = new B();
        Console.WriteLine("第二次调用。。。");
        b = new B();
    }
}

结果如下:

第一次调用。。。
-子类静态变量
--子类静态构造函数
---子类非静态变量
----父类静态变量
-----父类静态构造函数
------父类非静态变量
--------父类构造函数
---------子类构造函数
第二次调用。。。
-子类非静态变量
--父类非静态变量
---父类构造函数
----子类构造函数


从这里我们可以看到,静态变量和静态构造函数只会在类的第一次实例化时进行初始化,第二次就是正常的初始化了。在正常实例化中,初始化的顺序是:成员变量 -> 父类实例化 -> 构造函数。如果有静态类型的话,就会先初始化静态类型,于是顺序就变成了:静态变量 -> 静态构造函数 -> 成员变量 -> 父类实例化 -> 构造函数。在父类实例化中,顺序也是这样的。

2.1.一道笔试题

classA
{
    publicstatic int X;
    staticA()
    {
        X = B.Y + 1;
    }
}
classB
{
    publicstatic int Y = A.X + 1;
    staticB() { }
    staticvoid Main()
    {
        Console.WriteLine("X={0},Y={1}", A.X, B.Y);
    }
}

程序会从B类中的Main()开始执行,所以先初始化静态变量Y,而Y要调用A.X,调用A类静态构造函数A(),此时B.Y未初始化默认为0,所以X=1,再回到B的静态变量初始化中Y就是2了。初始化完成后,进入Main(),打印X=1,Y=2。意外吧!



3.总结

c#的初始化顺序看起来比较有规律,父类在子类中初始化,先静态后常规;而java则是先初始化全部静态类型(先父后子),再父类实例化,最后子类。








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值