java 静态变量加载_Java---类加载机制,构造方法,静态变量,(静态)代码块,父类,变量加载顺序...

本文通过多个Java代码示例,深入分析了静态变量的加载顺序。指出按照静态变量顺序初始化并赋予默认值,再赋予初始值,其位置影响构造方法赋值的有效性。还阐述了类实例化时,父类和子类的加载、初始化顺序,以及静态块、构造块和构造方法的执行顺序。

直接上代码:

代码1:

public classConstroctTest {private static ConstroctTest test = newConstroctTest();//静态变量sta1 未赋予初始值

public static intsta1;//静态变量sta1 赋予初始值20

public static int sta2 = 20;//构造方法中对于静态变量赋值

privateConstroctTest() {

sta1++;

sta2++;

}public static voidmain(String[] args) {

System.out.println(ConstroctTest.sta1);

System.out.println(ConstroctTest.sta2);

}

}

结果:

1

20

代码2:

public classConstroctTest {//静态变量sta1 未赋予初始值

public static intsta1;//静态变量sta1 赋予初始值20

public static int sta2 = 20;private static ConstroctTest test = newConstroctTest();//构造方法中对于静态变量赋值

privateConstroctTest() {

sta1++;

sta2++;

}public static voidmain(String[] args) {

System.out.println(ConstroctTest.sta1);

System.out.println(ConstroctTest.sta2);

}

}

结果:

1

21

结果分析:

1. 按照静态变量的顺序,初始化各静态变量。(给变量赋予默认值)

2. 按照顺序,赋予静态变量的初始值。

3. 以上结果在于:类静态变量的位置,决定着通过构造方法给sta1 与 sta2 赋予的值是否有效。

4. 在代码一中,先对于sta2 执行了 sta2 ++ 操作。而后给sta2 赋予静态变量值。(只因为顺序问题)

代码3:

public classConstroctTest {//静态变量sta1 未赋予初始值

public static intsta1;//静态变量sta1 赋予初始值20

public static int sta2 = 20;private static ConstroctTest test = newConstroctTest();//构造方法中对于静态变量赋值

privateConstroctTest() {

System.out.println("123456");

sta1++;

sta2++;

}public static voidmain(String[] args) {

System.out.println(ConstroctTest.sta1);

System.out.println(ConstroctTest.sta2);

System.out.println(ConstroctTest.sta1);

System.out.println(ConstroctTest.sta1);

}

}

结果:

446b1f71eb7df94b10238543549faeca.png

结果分析:

1. 从结果可以看出,Java的静态变量,只是在类第一次加载,初始化的时候执行。

2. 类变量不依赖类的实例,类变量只在初始化时候在栈内存中被分配一次空间,无论类的实例被创建几次,都不再为类变量分配空间。

3. 可以看出 ,类变量的执行与初始化,与实例对象没有关系。

代码4:

public classTest{public static voidmain(String[] args){

Child ch= newChild();

}

}classParent{static String name1 = "hello";static{

System.out.println("Parent static block");

}publicParent(){

System.out.println("Parent construct block");

}

}class Child extendsParent{static String name2 = "hello";static{

System.out.println("Child static block");

}publicChild(){

System.out.println("Child construct block");

}

}

结果:

5bdc6aeb250bbf9d657f66b1d844ff9e.png

结果分析:

1. 明先初始化父类的静态属性在执行自己的静态属性,再是父类的构造方法再是自己的构造方法。

2. 实例化 Child 类。第一要初始化类Child ,因为Child拥有父类(会判断父类是否初始化),类的初始化只有一次。。初始化类(就是按照顺序加载静态变量与静态方法)。

3. 初始化Child后。开始实例化Child ,因为拥有父类,所以调用构造方法之前会调用父类的默认构造方法。

代码5:

public class Animal {

private static int k;

static{

System.out.println("父类的静态方法");

}

{

System.out.println("执行父类的构造代码块");

}

public Animal(){

System.out.println("执行父类的构造方法");

}

public static void main(String[] args) {

System.out.println(Animal.k);

}

}

运行结果:

父类的静态方法

0

结果分析:

1. 构造代码块与构造方法对于类的加载 没有关系。

代码6:

public classAnimal {private static intk;

{

System.out.println("执行父类的构造代码块");

}static{

System.out.println("父类的静态方法");

}publicAnimal(){

System.out.println("执行父类的构造方法");

}public static voidmain(String[] args) {

Animal animal1= newAnimal();

Animal animal2= newAnimal();

}

}

结果:

5a57fbbe34883bb56d281c1260fb28a4.png

结果分析:

1. 构造代码块至于构造方法相关,随着构造方法的执行而执行。

代码7:

public classCat {private static inta;private static int b = 1000;static{

a= 100;

b= 200;

}public static voidmain(String[] args) {

System.out.println(Cat.a);

System.out.println(Cat.b);

}

}

3a49608718290ec48659f0ade44e6798.png

结果分析:

1. 可以把静代码块中的内容 看做是赋予操作。

2.  当静态代码块在a,b前面。此时输出的结果是100 1000

代码8:

packagecom.fande.amazon.ws.member.rs;classA {static{

System.out.println("A的静态块");

}private static String staticStr =getStaticStr();private String str =getStr();

{

System.out.println("A的实例块");

}publicA() {

System.out.println("A的构造方法");

}private staticString getStaticStr() {

System.out.println("A的静态属性初始化");return null;

}privateString getStr() {

System.out.println("A的实例属性初始化");return null;

}public static voidmain(String[] args) {newB();newB();

}

}class B extendsA{private static String staticStr =getStaticStr();static{

System.out.println("B的静态块");

}

{

System.out.println("B的实例块");

}publicB() {

System.out.println("B的构造方法");

}private String str =getStr();private staticString getStaticStr() {

System.out.println("B的静态属性初始化");return null;

}privateString getStr() {

System.out.println("B的实例属性初始化");return null;

}

}

通过上面的分析,结果应该很明确了:

ef58c5933135fa9c0cd0b4aacddb85b6.png

总结:

由此可见,实例化子类的时候,若此类未被加载过,首先加载是父类的类对象,然后加载子类的类对象,接着实例化父类,最后实例化子类,若此类被加载过,不再加载父类和子类的类对象。

接下来是加载顺序,当加载类对象时,首先初始化静态属性,然后执行静态块;当实例化对象时,首先执行构造块(直接写在类中的代码块),然后执行构造方法。至于各静态块和静态属性初始化哪个些执行,是按代码的先后顺序。属性、构造块(也就是上面的实例块)、构造方法之间的执行顺序(但构造块一定会在构造方法前执行),也是按代码的先后顺序。

参考:

http://www.cnblogs.com/maowh/p/3729971.html

http://blog.sina.com.cn/s/blog_68117d6d0102uzbq.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值