javaJavaSE程序员

Java初始化理解与总结

2015-08-04  本文已影响1825人  梦工厂

Java的初始化可以分为两个部分:
(a)类的初始化
(b)对象的创建
(a)类的初始化


**一、概念介绍: ** 一个类(class)要被使用必须经过装载,连接,初始化这样的过程。

二、类的初始化条件:
类会在首次被“主动使用”时执行初始化,以下情况第一次发生之前类会被初始化:

  1. 创建类的实例;
  2. 调用类的静态方法;
  3. 调用类的静态变量,并且该变量不是一个常变量
  4. 为类的静态字段赋值;
  5. 在顶层类中执行assert语句;(?)
  6. 调用类Class及包java.lang.reflect中的某些反射方法;

JLS严格的说明:在任何其他的情况下,都不会对类或接口进行初始化。

三、类的初始化规则:

  1. 类初始化时,该类的父类将首先被初始化,此过程一直递归到 java.lang.Object为止。但是父类实现的接口并不会被初始化。
class Parent implements J{
    { System.out.println("父类初始化块"); }  
    static{
        System.out.println("父类静态初始化块");  
    }
}
class Child extends Parent implements I{
    { System.out.println("子类初始化块"); }  
    static{
        System.out.println("子类静态初始化块");  
    }
}
interface I {  
    int i = Test.out("interface : i", 1);  
}  
interface J {  
    int j = Test.out("interface : j", 2);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        new Child();
    }
}
接口只有被用到时才会被初始化
输出: 
父类静态初始化块
子类静态初始化块
父类初始化块
子类初始化块
interface I {  
    int i = Test.out("interface : i", 1);  
    int ii = Test.out("interface : ii", 11);  
}  
interface J extends I{  
    int j = Test.out("interface : j", 2);  
    int jj = Test.out("interface : jj", 22);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(J.j);  
    }
}
输出:
interface : j=2
interface : jj=22
2
class Parent{
    static int p = 10;
    static{
        System.out.println("父类静态初始化块");  
    }
}
class Child extends Parent{ 
    static int c = 20; 
    static{
        System.out.println("子类静态初始化块");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.p);    //静态域p被子类引用
    }
}
父类静态初始化块
10

示例2:(满足类的初始化条件,父类也会被初始化,与示例1不同)

public class Test { 
    public static void main(String [] args){
        System.out.println(Child.c); 
    }
}
父类静态初始化块
子类静态初始化块
20
class Parent{
    static{
        System.out.println("父类静态初始化块");  
    }
}
class Child extends Parent{
    static final int x = 2005;  
    static{
        System.out.println("子类静态初始化块");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.x); 
    }
}
输出:
2005

示例2:(I.i是一个编译时常量,因此它不会引起I被初始化。)

interface I {  
    int i = 1;  
    int ii = Test.out("ii", 2);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(I.i);  
    }
}
1
class Child extends Parent{ 
    static int c = 20; 
    static{
        System.out.println("子类静态初始化块");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.c); 
        System.out.println(Child.c); 
    }
}
父类静态初始化块
子类静态初始化块
20
20

示例2:

interface J{   
    int j = Test.out("j", 3);  
    int jj = Test.out("jj", 4);  
}    
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(J.j);  
        System.out.println(J.j);  
    }
}
j=3
jj=4
3
3

(b)对象创建过程中的Java初始化

一. 对象的创建过程总结

假设有个名为Dog的类:

  1. 当首次创建类型为Dog的对象时,或者Dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位Dog.class文件。
  2. 然后载入Dog.class(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在class对象首次加载的时候进行一次。
  3. 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
  4. 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值(对数字来说就是0,对布尔型与字符型也相同),而引用则被设置成了null。
  5. 执行所有出现于字段定义处的初始化动作。
  6. 执行构造器。
    ---《Thinking in java》

二. 对象创建过程中初始化顺序
父静态成员>子静态成员>父普通成员初始化>父构造>子普通成员初始化>子构造.
( 静态初始化块以静态变量对待)

public class Test { 
    public static void main(String [] args){
        new Child();
    }
}
class Parent{
    { 
        System.out.println("父类普通成员初始化块"); 
    }  
    static{
        System.out.println("父类静态成员及初始化块");
    }
    
    public Parent(){
        System.out.println("父类构造函数"); 
    }
}
class Child extends Parent{
    { 
        System.out.println("子类普通成员初始化块"); 
    }  
    static{
        System.out.println("子类静态成员及初始化块");
    }
    
    public Child(){
        super();
        System.out.println("子类构造函数"); 
    }
}
父类静态成员及初始化块
子类静态成员及初始化块
父类普通成员初始化块
父类构造函数
子类普通成员初始化块
子类构造函数
public class Test { 
    public static void main(String [] args){
        new Child();
    }
}
class Parent{
    public Parent(){
        System.out.println("父类构造函数"); 
        System.out.println("子类成员变量 height:" + ((Child)this).height);
    }
}
class Child extends Parent{
    public int height= 20;
    { 
        System.out.println("子类非静态成员初始化块"); 
        System.out.println("子类成员变量 height:" + this.height);
    }  
    
    public Child(){
        super();
        System.out.println("子类构造函数"); 
    }
}
父类构造函数
子类成员变量 height:0
子类非静态成员初始化块
子类成员变量 height:20
子类构造函数

三. 对象创建过程的说明

  1. 静态域的初始化是在类的初始化期间,非静态域的初始化时在类的实例创建期间。这意味这静态域初始化在非静态域之前。
public class Test { 
    public static void main(String [] args){
        System.out.println(Parent.a); 
    }
}
class Parent{
    public static int a = 10;
    {
        System.out.println("父类普通成员初始化块");
    }
    public Parent(){
        System.out.println("父类构造函数"); 
    }
}
输出:10
public class Test { 
    public static void main(String [] args){
        new Parent(); 
    }
}
class Parent{
    {
        System.out.println("普通成员初始化块1");
    }
    public Parent(){
        System.out.println("构造函数"); 
    }
    {
        System.out.println("普通成员初始化块2");
    }
}
普通成员初始化块1
普通成员初始化块2
构造函数
public class Test {    
  public static void main(String [] args){
      Parent parent = new Child();
  }
}
class Parent{
  { 
      System.out.println("父类普通成员初始化块"); 
  }  
  static{
      System.out.println("父类静态成员及初始化块");
  }

  public Parent(){
      System.out.println("父类构造函数"); 
  }
}
class Child extends Parent{
  { 
      System.out.println("子类普通成员初始化块"); 
  }  
  static{
      System.out.println("子类静态成员及初始化块");
  }

  public Child(){
      super();
      System.out.println("子类构造函数"); 
  }
}
父类静态成员及初始化块
子类静态成员及初始化块
父类普通成员初始化块
父类构造函数
子类普通成员初始化块
子类构造函数

可见多态情况下的初始化与示例1中继承情况下的初始化是一样的,因为都是创建的子类的实例。

public class Test {    
    public static void main(String [] args){
      System.out.println("Test- main");
    }
  
    static{
      System.out.println("静态成员及初始化块");
    }
}
静态成员及初始化块
Test- main

2015/8

上一篇下一篇

猜你喜欢

热点阅读