`
yuwei2008vip
  • 浏览: 38859 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

java类初始化

阅读更多
Java类初始化深入分析 初始化(initialization)其实包含两部分:
1.类的初始化(initialization class & interface);
2.对象的创建(creation of new class instances)。
类的初始化其实是类加载(loading of classes),它是"对象的创建"的第一步。
顺序:类的加载肯定是第一步的,所以类的初始化在前,然后是对象的初始化。大体的初始化顺序是:类初始化 ->对象的初始化
(1)类初始化类初始化分为两个部分:
一是初始化类的静态成员或者静态块;
另外就是初始化接口,也就是初始化接口里的成员;
A) 初始化类的静态成员。
例如:
class 
{ 
	static int a = 0; 
	static 
	{ 
		int a = 1; 
	} 
} 

B)初始化接口里的成员。
例如:
public interface A 
{ 
	MyClass myClass = new MyClass(); 
} 
class Initialization implements A{}

类初始化原则:
--initialization classes 时,该class的superclass 将首先被初始化,但其实现的interface则不会。
--initialization classes时,该class的superclass,以及superlcass的superclass 会首先被递归地初始化,一直到java.lang.Object为止。但initialiazation interface的时候,却不需如此,只会初始化该interface本身。
--对于由引用类变量(class field)所引发的初始化,只会初始化真正定义该field的class。
--如果一个static field是编译时常量(compile-time constant),则对它的引用不会引起定义它的类的初始化。 --类变量的初始化是先把静态成员设置默认值,然后再对其赋值。 引起定义它的类的初始化。 --类变量的初始化是先把静态成员设置默认值,然后再对其赋值。
可以看下面的例子:
例一:
class One   
{   
  One(String str)   
  {   
	System.out.println(str);   
  }   
}   
  
class Two 
{ 
	static int i = 0; 
	One one_1 = new One("one-1"); 
	static One one_2 = new One("one-2"); 
	static One one_3 = new One("one-3"); 

	Two(String str) 
	{ 
		System.out.println(str); 
	} 
} 

public class TestStatic 
{ 
	public static void main(String[] args) 
	{ 
		System.out.println("Test   main()   start..."); 
		System.out.println("Two.i   =   " + Two.i); 
	} 
} 
首先java虚拟机要执行TestStatic里面的static方法main(),这会导致TestStatic这个类的加载,从而会进行类变量的初始化。由于TestStatic里面没有静态成员,也没有继承自某个类,所以该过程什么事情都不做;
第二执行TestStatic里面的main();打印出“"Test   main()   start...”;
第三执行Two.i,由于引用到Two的静态成员,所以会对Two这个类的加载,从而要对它的静态成员进行初始化,初始化过程为:先把静态成员变量设置为默认值;然后对i,one_2,one_3进行显示的初始化,打印出“one-2”,“one-3”;
第四静态成员初始化完成后,执行返回到main()方法的System.out.println("Two.i   =   "   +   Two.i);语句,打印出“Two.i   =   0”

例二:
public class Singleton 
{ 
	private static Singleton obj = new Singleton(); 
	public static int count1; 
	public static int count2 = 0; 

	private Singleton() 
	{ 
	count1++; 
	count2++; 
	} 

	public static Singleton getInstance() 
	{ 
	return obj; 
	} 

	public static void main(String[] args) 
	{ 
		Singleton obj = getInstance(); 
		System.out.println("Inside Singleton,count1=" + obj.count1); 
		System.out.println("Inside Singleton,count2=" + obj.count2); 
	} 
} 
首先JVM要执行Singleton里面的main(),这会导致对Singleton的加载,执行静态成员的初始化;
第二给成员变量分配空间,并且赋默认值。把obj置为null,count1=0, count2=0;
第三顺序执行赋值语句,首先执行private static Singleton obj = new Singleton();结果count1=1, count2=1;
第四执行count2=0;赋值语句;结果变成count1=1, count2=0;
注意:由于count1不存在赋值语句,所以count1是不会发生变化的。
(2)对象创建
具体步骤如下:
(A) 所有的成员变量—包括该类,及它的父类中的成员变量--被分配内存空间,并赋予默认值。
(这里是第一次初始化成员变量)
(B) 为所调用的构造函数初始化其参数变量。(如果有参数)
(C) 如果在构造函数中用this 调用了同类中的其他构造函数,则按照步骤(B)~(F)去处理被调用到的构造函数。
(D) 如果在构造函数中用super调用了其父类的构造函数,则按照步骤(B)~(F)去处理被调用到的父类构造函数。
(E) 按照书写顺序,执行赋值语句或者初始化块来初始化成员变量。(这里是第二次初始化成员变量)
(F) 按照书写顺序,执行constructor的其余部分。

*注意*
成员变量其实都被初始化2次,第一次是赋予默认值,第二次才是你想要设定的值。
例一:
class Insect 
{ 
	int i = 9; 
	int j; 

	Insect() 
	{ 
		System.out.println("Insect   initialized"); 
		prt("i   =   " + i + ",j   =   " + j); 
		j = 39; 
	} 	

	static int x1 = prt("static   Insect.x1   initialized"); 

	static int prt(String s) 
	{ 
		System.out.println(s); 
		return 47; 
	} 
} 

public class Beetle extends Insect 
{ 
	int k = prt("Beetle.k   initialized"); 

	Beetle() 
	{ 
	System.out.println("Beetle   initialized"); 
	prt("k   =   " + k); 
	prt("j   =   " + j); 
	} 

	static int x2 = prt("static   Beetle.x2   initialized"); 

	public static void main(String[] args) 
	{ 
		prt("Beetle   constructor"); 
		Beetle b = new Beetle(); 
	} 
} 
  

首先JVM执行Beetle里面的静态方法main(),这会导致对Beetle类的加载,加载Beetle后发现它还有基类Insect,接着JVM会加载基类Insect,如果Insect还有基类,这个加载过程会一直递归下去,直到父类为Object为止;
第二类加载完成后,变量的内存空间已经分配并且初始值为默认值,接着以从基类到子类的顺序进行静态成员的赋值;所以打印出“static   Insect.x1   initialized”,“static   Beetle.x2   initialized”;
第三静态成员变量赋值完成后,程序执行点回到main(),打印“Beetle   constructor”;
第四创建一个Beetle对象,这会调用Beetle的构造方法,由于Beetle有基类,故会调用基类的构造方法,这个过程会一直递归下去,直到父类为Object为止。注意在调用过程中构造方法的方法体是没有执行的;
第五对基类Insect的非静态成员进行显示赋值。这样i   =   9; j=0;然后执行基类的构造方法的方法体,打印出“I = 9,j = 0”,并给j 赋值为39;
第六基类非静态成员成员初始化完后会对子类Beetle的非静态成员赋值,故打印出“Beetle.k   initialized”,并且k被赋值为47;赋值操作完成后执行构造方法体,打印出“Beetle   initialized”,“k=47”,“j=39”,初始化完成。
例二:
class A 
{ 
	A() 
	{ 
		System.out.println("A.A called"); 
	} 
	   
	A(int i) 
	{ 
		this(); 
		System.out.println("A.A(int) called"); 
	} 
} 
   
class B extends A 
{ 
  int i = f(); 
  int j; 

  { 
		j = 37; 
   	System.out.println("initialization block executed"); 
  } 
   
	B() 
	{ 
		this(10); 
		System.out.println("B.B() called"); 
	} 
   
  B(int i) 
	{ 
		super(i); 
		System.out.println("B.B(int) called"); 
	} 
	int f() 
	{ 
		System.out.println("B.f called"); 
		return 47; 
	} 
} 

public class CtorDemo3 
{ 
  public static void main(String args[]) 
	{ 
   	B bobj = new B(); 
  } 
} 

首先JVM执行CtorDemo3里面的静态方法main(),这会导致对CtorDemo3类的加载。由于CtorDemo3没有静态成员,故不用做静态成员的初始化;
第二创建B的对象,这会加载B类,因为B类有基类A,所以也要加载基类A;
第三类加载完毕后所有成员变量都分配了内存空间,赋了默认的初值。由于基类和子类都没有静态成员,所以都不用做静态成员的初始化;
第四调用构造方法B(),由于方法中this(10),故会调用B(int i)这个构造方法,在B(int i)这个方法中有super(i)这条调用语句,所以会调用类A的构造方法A(int i),在这个构造方法中有this();这条语句,所以会调用A(),打印出“A.A called”,接着执行A(int i)的构造方法体“A.A(int) called”;
第五调用返回到类B后会执行B的赋值语句和初始化块,打印“B.f called”,并且给i赋值47,执行初始化块会打印“initialization block executed”;
第六执行B(int i)构造方法的方法体,打印“B.B(int) called”;
第七执行B()构造方法的方法体,打印“B.B() called”;
分享到:
评论
1 楼 yl380291073 2010-12-05  
非常感谢你文章,今天花了一天的时间学习和分析。收获颇多.谢谢了。

相关推荐

    java数组初始化详解

    Java 数组初始化详解 Java 数组初始化是 Java 编程语言中的一种基本概念,它允许开发者创建和初始化数组,以便于存储和操作数据。在本文中,我们将对 Java 数组初始化进行详细的介绍,包括一维数组和二维数组的声明...

    java面试题-类的初始化顺序.doc

    类--初始化块"); 39. } 40. // 构造器 41. public SubClass() { 42. System.out.println("子类--构造器"); 43. } 44. 45. public static void main(String[]...因此,掌握类的初始化顺序是每个Java开发者必备的知识点。

    Java类初始化时机测试方法解析

    Java类初始化时机测试方法解析 Java类初始化时机测试方法解析是Java编程语言中一个重要的概念,涉及到类的加载、链接、初始化等过程。下面我们将对Java类初始化时机测试方法进行详细的解析。 首先,我们需要了解...

    Java类初始化顺序

    Java类的初始化顺序是编程中一个非常重要的概念,它涉及到对象的创建过程和成员变量的初始化。当一个Java类被实例化或者其静态成员被访问时,类的初始化过程就开始了。以下详细解释了Java类的初始化顺序: 1. **...

    深入java虚拟机(三)——类的生命周期(下)类的初始化1

    5. **初始化类的子类**。 6. **JVM启动时作为主类的类**。 例如,如果我们有一个`Singleton`类,其中包含静态变量和静态初始化代码块,如下所示: ```java class Singleton { private static Singleton singleton...

    Java类初始化和实例化中的2个“雷区”

    Java类初始化和实例化是程序开发中至关重要的环节,它涉及到类加载、静态变量的初始化以及构造器的执行。在Java中,类的初始化通常在以下几个情况发生: 1. 使用`new`关键字创建实例。 2. 访问或修改类的静态字段...

    java程序初始化顺序

    在Java编程语言中,程序初始化的顺序是一个关键概念,它涉及到类加载、对象创建以及执行流程的安排。了解这些顺序对于编写高效、无错误的代码至关重要。以下是对Java程序初始化顺序的详细说明: 1. **类加载阶段**...

    Java类继承初始化顺序

    静态初始化块用于初始化类级别的静态变量,它们只在类加载时执行一次。 2. **成员变量初始化**:接下来,初始化父类的非静态成员变量,这是通过调用父类的构造器实现的。Java规定每个子类实例在构造之前必须先调用...

    JAVA面试题解惑系列——类的初始化顺序

    首先,需要了解Java类初始化的基本规则,即在类的静态变量、静态初始化块、变量、初始化块、构造器这五个部分中,它们的初始化顺序依次是:静态变量、静态初始化块、变量、初始化块、构造器。这个顺序在单个类中是...

    Java静态初始化块和对象初始化块

    在Java编程语言中,初始化块是程序执行时用于初始化对象或类的重要机制。这里我们将深入探讨两种类型的初始化块:静态初始化块(Static Initializer Block)和对象初始化块(Instance Initializer Block)。这两种...

    Java变量初始化

    Java 变量初始化的时机可以分为两类:实例变量初始化和类变量初始化。 实例变量初始化 实例变量初始化可以在三个地方进行: 1. 定义实例变量的时候指定初始值; 2. 非静态初始化代码块中对实例变量指定初值; 3. ...

    java中类的初始化顺序

    ### Java中类的初始化顺序详解 #### 一、概述 在Java编程语言中,类的初始化是一个非常重要的概念。类的初始化涉及到多个方面,包括静态成员变量、实例成员变量、静态初始化块、实例初始化块以及构造函数等。本文...

    java代码的初始化顺序demo

    它用于初始化类级别的静态变量。在`init`目录下的文件可能包含了不同静态初始化的示例。 3. **实例化阶段**: 当我们创建一个新的对象时,Java会进行实例初始化。首先,分配内存空间,然后调用构造函数。实例初始...

    java类变量初始化顺序

    详细讲解java类中静态变量,普通标量,对象、基本类型的初始化顺序。

    java 初始化与方法

    构造方法用于初始化类的新实例,普通方法执行特定任务,静态方法与类关联而非实例,抽象方法则在接口或抽象类中定义,需由子类实现。方法的参数传递、返回值和重载也是重要的知识点,理解这些能帮助我们编写更灵活...

    简单了解java类的初始化以及类的实例化

    Java类的初始化和实例化详解 Java类的初始化和实例化是Java编程语言中两个非常重要的概念,它们都是Java类生命周期的重要组成部分。下面我们将详细介绍Java类的初始化和实例化的过程,并解释其中的细节。 一、Java...

    6种方法初始化JAVA中的list集合

    本文将详细介绍6种初始化Java List集合的方法,并通过代码示例帮助理解每种方法的使用和特点。 1. 常规方式 这是最常见的初始化List的方式,通过创建ArrayList实例并逐个添加元素。自JDK 7以后,可以省略泛型类型的...

Global site tag (gtag.js) - Google Analytics