Java类的初始化、变量的初始化

本文简单演示Java类的初始化、变量的初始化顺序,扎实Java 基础,编写高效的code哦


知识点

  • Java常量,final 修饰,值被设定后不能再被修改
  • 静态变量里,static 修饰,顾名思义,无须创建对象,便可在内存中申请一个存储空间进行存储
  • 成员变量,也称实例变量,它随着当前对象的建立而建立,随着对象的销毁而销毁,存在于对象所在的堆内存中
  • 构造器,创建class对象时执行
  • 静态初始化块,执行优先级高于非静态的初始化块,它会在对象装载到 jvm的时候执行一次,执行完成便销毁,只能初始化 static 修饰的变量
  • 非静态初始化块,执行的时候如果有静态初始化块,先执行静态初始化块再执行非静态初始化块,在每个对象生成时都会被执行一次,它可以初始化类的实例变量。但它会在构造函数执行之前被执行。

类的初始化顺序

Java中类初始化顺序,依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。。

实例代码

父类 Human

package com.lazy.pojos;

import com.lazy.interfaces.IBehaviour;

/**
 * Created by system on 16/9/10.
 */
public class Human /*extends Object*/ implements IBehaviour { //default super class Object
    String TAG = "Human";
    public static String sTAG = "static Human";
    protected long identifier = System.currentTimeMillis();//身份标识
    protected int age;
    protected int height;
    protected String name;

    /* 静态初始化块 */
    static {
        System.out.println("Human" + " 静态初始化块");
    }

    /* 初始化块 (实例初始化器)*/ {
        System.out.println(TAG + " 初始化块");
        System.out.println(TAG + " " + identifier);
    }

    public Human() {
        System.out.println(TAG + " 构造器");
    }

    @Override
    public void eat() {

    }
}

子类Woman

package com.lazy.pojos;

/**
 * Created by system on 16/9/10.
 */
public class Woman extends Human  {

}

子类Man

package com.lazy.pojos;

/**
 * Created by system on 16/9/10.
 */
public class Man extends Human {
    /* 静态变量 */
    public static String staticVar = "staticVar";

    /* 成员变量 */
    public String field = "field";

    String TAG = "Man";

    /* 静态初始化块 */
    static {
        System.out.println("Man 静态初始化块");
        System.out.println("Man staticVar =" + staticVar);
    }

    /* 初始化块 (类实例初始化器)*/ {
        System.out.println(TAG + " 初始化块");
        System.out.println(TAG + " field = " + field);
    }

    /* 构造器 */
    public Man() {
//        super(); //隐式
        System.out.println(TAG + " 构造器");
    }
}

测试类:FinalVarTest

public class InitializeOrderTest {

    public static void main(String[] args) {
        new Man();
        new Woman();
    }
}

执行结果:如图
这里写图片描述

Java 类的初始化,可以分为单一对象的初始化,已经有继承关系的对象初始化,然而java 所有类的基类都是Object。有基类的先初始化基类,再初始化自身。Woman 类之所以能调用基类构造器,皆因为Java 编译器,class 文件中生成了一个默认构造器。如下图

这里写图片描述

IntelliJ IDEA 能直接查看class 文件,而且调试功能更为强大

变量初始化顺序

实例代码
package com.lazy.pojos;

public class FinalVar {
    String mg = "msg";

    static String msg = "static msg";

    final static String msg2 = "final static msg";

    public static final String MSG = "MSG";

    public static final String MSG2 = "MSG" + 2; //MSG2 = "MSG2"

    public static final String MSG3 = "MSG" + "3"; // MSG3 = "MSG3"

    public static final String MSG4 = msg + "4"; //MSG4; 只 declare no value

    public static final String MSG5 = msg2 + "5"; //MSG5 = "final static msg5";

    public static String MSG6 = msg2 + "6"; //MSG6; 只 declare no value

    public final String MSG7 = msg2 + "7"; ///MSG7 = "final static msg7";

    public final String MSG8 = mg + "8"; //MSG8; 只 declare no value

    public static final int NUM = 100 * 10; //NUM =1000;

    public int num = 100 * 10; //NUM; 只 declare no value

    final String MG = "MG";

    static {
        System.out.println("static");
    }
}

对于变量我们如何测试变量的初始化顺序呢
- 查看Class 反编译后的代码
- Debug 变量

class 文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.lazy.pojos;

public class FinalVar {
    String mg = "msg";
    static String msg = "static msg";
    static final String msg2 = "final static msg";
    public static final String MSG = "MSG";
    public static final String MSG2 = "MSG2";
    public static final String MSG3 = "MSG3";
    public static final String MSG4;
    public static final String MSG5 = "final static msg5";
    public static String MSG6;
    public final String MSG7 = "final static msg7";
    public final String MSG8;
    public static final int NUM = 1000;
    public int num;
    final String MG;

    public FinalVar() {
        this.MSG8 = this.mg + "8";
        this.num = 1000;
        this.MG = "MG";
    }

    static {
        MSG4 = msg + "4";
        MSG6 = "final static msg6";
        System.out.println("static");
    }
}

测试代码

public class FinalVarTest {

    public static void main(String[] args) {
        System.out.println(FinalVar.MSG);
//        System.out.println(FinalVar.MSG4);
//        new FinalVar();
    }
}

由此可得:
1.static final 变量在编译时,编译器已经为之初始化值,static 变量要比成员变量优先初始化,仅初始化一次。——若代码中引用到 一个 static 变量,便会初始化整个类的static 变量,static final 变量则不会。
看代码
①如 static final 变量 MSG2 , 编译器自动为它 拼接成:MSG2。②再看 MSG4 ,它由 static 变量 msg + “4” ,msg 值不是final ,常量值,编译器只好先declare MSG4 这个变量,在 static 代码块中进行赋值; ③而 MSG5 变量的默认值为 “final static msg5”,④即 static final 变量在赋值时,值必须编译前就明确了. 若采用 static 变量进行赋值,—— 只能static 代码块中进行赋值。

2.对于 成员变量 MSG8 ,以下的声明的成员变量 如 num 打开class 文件看到都只在class 构造器中被赋值,经我测试只有成员变量赋值时引用了其它变量时,都会在构造器中被赋值。

如果你还不明白变量初始化顺序,可以在变量上打变量断点
这里写图片描述

debug运行代码便会挂起

最后

对于 变量的初始化来说,情况比较多,还得多实践。如果想了解jvm 类加载的请阅读 [ JVM 类加载的那些事 ]

对于本文的字符串拼接其细节的请参考 [ 浅谈Java String内幕 ], [ 什么是字符串常量池? ] 两篇文章。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值