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

来源:互联网 发布:linux的dd创建多个文件 编辑:程序博客网 时间:2024/05/18 00:38

本文简单演示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内幕 ], [ 什么是字符串常量池? ] 两篇文章。

1 0
原创粉丝点击