关于Java Initializer(Java 初始化程序)的理解

来源:互联网 发布:telnet 端口号 编辑:程序博客网 时间:2024/05/22 10:35

    程序中的初始化是指对类中域field(就是属性property)和局部变量(local variable)赋初值。在Java中初始化分为显式初始化(Explicitly)和隐式初始化(Implicitly

 

域的隐式初始化(Field Implicit Initialization

       Java虚拟机负责对域进行隐式初始化;隐式初始化总是在任何代码之前,因为虚拟机要保证数据的正确性,这成全了粗心的coder不必为初始化担心。

实例域(instance field)的隐式初始化:

其原理是当实例化一个类时(不论以何种方式遇到new关键字时),虚拟机就会在相应的堆内存上为该类对象开辟一块空间,内存空间大小在编译阶段就能知道,因为类中属性为原始数据类型和引用类型,引用类型存放的地址占内存字节数是确定的(究竟多少我也不清楚)原始数据类型所占用的内存大小是固定的。当虚拟机为对象分配完内存空间后,接着会对此块内存清零,清零的结果导致所有的对象属性将获得一个初始值,至此,实例域的隐式初始化就完成了,初始值也可以获得。

 

       静态域(static field)的隐式初始化

       当类中定义了静态域之后,事情开始变得复杂了;这可以与类中的静态代码块(static{…})一起来说;当主程序中第一次使用虚拟机的类池中不存在的类时(不管是实例化此类的对象,还是调用类中静态方法),类加载器ClassLoader(其实是应用类加载器的一个实例)就会将此类在类池中引入,其做法就是为此类创建一个Class类对象;这样也就是在堆内存中开辟了一个空间,存放Class的一个实例,此实例中保存的是刚才ClassLoader加载的类信息;静态域作为类信息,按照上面讲的“实例域的隐式初始化”过程来初始化,接着执行静态代码块。为什么先初始化静态域,然后再执行静态代码块,可以请读者先想一想,将在此文后头进行讲解。

 

域的显式初始化(Field Explicit Initialization

       实例域的显式初始化

       实例域的显式初始化可以在类中定义该域时进行,也是就为该域显式地为该域赋值;也可以在类构造体中为其初始化;类构造体包括构造方法和公共构造体(很多人不知道公共构造体的概念,其实就是在类定义体中,加上一对大括号,然后在括号中编写代码,公共构造体的作用是将构造方法中相同部分提取出来(factor out),放在一个不同的构造方法中供重用,调用不同的构造方法时,都会先执行公共构造体中的代码);那么域的显式初始化顺序可以获知了:先执行定义时初始化,再执行构造体中的初始化。

       静态域的显式初始化

       静态域的显式初始化是在ClassLoader将类载入虚拟机类池的时候进行的,我们也可以在静态域定义处为该域赋初值,或者在static区内为静态域赋值;当ClassLoader在堆内存区为该类创建Class对象时,对静态域首先执行隐式初始化,接着对静态域进行显式初始化,次序是先执行定义处赋值,再执行static区内赋值。

      

       由此我们可以得出结论:其实类域的初始化是在必要时才进行的,我们可以把静态域的初始化也理解成实例域的初始化,静态域就是某个Class对象的实例属性,而static代码块是虚拟机为创建Class类对象时所执行的构造体,所以也按照1.开辟内存空间给域并清零;2.执行域定义处的赋值;3.执行构造体内的赋值;对于后两项,只有在coder写出相应的代码时才会执行。

       可以查看下面一段代码来验证以上的赋值顺序,但是对于第一步,则无法与后两步结合验证。

package initializationDemo;

 

class Item{

   

    public Item(){

       System.out.println("Item()");

    }

   

    public Item(int id){

       System.out.println("Item("+id+")");

    }

}

 

class ItemLocker{

   

    static Item item1=new Item();

    Item item2=new Item();

   

    static{

       item1=new Item(1);

    }

   

    {

       System.out.println("this is the instance field block");

    }

   

    public ItemLocker(){

       item2=new Item(2);

    }

}

 

public class MainClass {

    public static void main(String[] args){

       try {

           Class.forName("ItemLocker");

       } catch (ClassNotFoundException e) {

       }

      

       ItemLocker il=new ItemLocker();

    }

}

运行结果为:

Item()

Item(1)

Item()

this is the instance field block

Item(2)

 

最后,局部变量只支持显式初始化。局部变量在声明定义之后可以进行显式的初始化(explicitly initialized),也可以在使用前进行赋值,但是注意java虚拟机需要保证局部变量在被使用之前必须经过初始化了,这在《Thinking in java》第四版中明确说明过,这么做是为了提醒程序员可能出现的漏洞,是一种代码安全机制。

 

 

 

 

参考《Thinking in java》第四版

《张孝祥Java基础课程》