`
lvwenwen
  • 浏览: 955716 次
  • 性别: Icon_minigender_1
  • 来自: 魔都
社区版块
存档分类
最新评论

Java类的初始化

阅读更多
Java类的初始化

我们知道一个类(class)要被使用必须经过装载,连接,初始化这样的过程。下面先对这三阶段做一个简单的描述,之后会结合一个简单的例子来说明java中类的初始化过程。

在装载阶段,类装载器(Bootstrap ClassLoader 或者用户自定义的ClassLoader) 把编译形成的class文件载入内存,创建类相关的Class对象,这个Class对象封装了我们要使用的类的类型信息。

连接阶段又可以分为三个子步骤:验证、准备和解析。
验证就是要确保java类型数据格式 的正确性,并适于JVM使用。
准备阶段,JVM为静态变量分配内存空间,并设置默认值,注意,这里是设置默认值,比如说int型的变量会被赋予默认值0 。在这个阶段,JVM可能还会为一些数据结构分配内存,目的 是提高运行程序的性能,比如说方法表。
解析过程就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用。这个阶段可以被推迟到初始化之后,当程序运行的过程中真正使用某个符号引用的时候 再去解析它。

类会在首次被“主动使用”时执行初始化,为类(静态)变量赋予正确的初始值。在Java代码中,一个正确的初始值是通过类变量初始化语句或者静态初始化块给出的。而我们这里所说的主动使用 包括:
1.        创建类的实例
2.        调用类的静态方法
3.        使用类的非常量静态字段
4.        调用Java API中的某些反射方法
5.        初始化某个类的子类
6.        含有main()方法的类启动时

初始化一个类包括两个步骤:
1、  如果类存在直接父类的话,且直接父类还没有被初始化,则先初始化其直接父类
2、  如果类存在一个初始化方法,就执行此方法
注:初始化接口并不需要初始化它的父接口。

好,下面我们通过一些简单的例子来重点看一下初始化的过程 。
好,先上代码(超级简单的代码)。
[java] view plaincopy
package kevin.demo; 
  
class Base { 
    int a; 
    static int b; 
    static int c = 1; 
  
    static { 
       b=2; 
       c = 3; 
       System.out.println("Base:static init block invoked.."); 
    } 
  
    void display() { 
       System.out.println("Base:a=" + a + ",b=" + b + ",c=" + c); 
    } 
  

  
class Derived extends Base { 
    int d; 
    static int e = 4; 
  
    static { 
       e= 5; 
       System.out.println("Derived:static init block invoked..."); 
    } 
  
    void display() { 
       super.display(); 
       System.out.println("Derived:d=" + d + ",e=" + e); 
    } 




好,这里我们定义了一个简单的基类Base,然后定义了一个类Derived继承它。这个已经简单到我不知道说什么了,直接上main方法吧。

[java] view plaincopy
public class Demo { 
    public static void main(String[] args) { 
       new Derived().display(); 
    } 



好,我们执行这个方法,看会输出什么。。上个图看一下:

如图所示,虽然我们调用的子类的构造函数创建对象 ,但是父类中的有关初始化的语句和静态初始化块也会被执行或调用,这正与前面所说的:如果一个类的直接父类还没有被初始化,那么 先初始化它的父类。而为什么这些初始化的动作会执行,就是因为我们主动使用了Derived这个类。而我们上面列出了好几个主动使用的情况,好下面我们修改一下main方法,看上面所言是否正确。
注:因为我们在这里谈论的主题是类的初始化,所以关于对象的初始化过程我们这里暂不讨论。

好,看下修改后的Demo:
[java] view plaincopy
public class Demo { 
    static int f; 
    static{ 
       f=100; 
       System.out.println("Demo:static init block invoked..and f="+f); 
    } 
    
    public static void main(String[] args) { 
       System.out.println("maininvoked.."); 
    }} 

好,看执行结果:

好,我们可以看到,含有main函数的类会首先执行初始化。
[java] view plaincopy
public class Demo { 
    static int f; 
    static{ 
       f=100; 
       System.out.println("Demo:static init block invoked..and f="+f); 
    } 
    
    public static void main(String[] args) { 
       System.out.println(Derived.e); 
    } 


下面再看一下,使用Derived的静态变量会不会引起初始化过程。。

果然,这也属于主动使用的一种,所以类执行了初始化,并且这里看的更加清楚 ,含有main方法的类首先被初始化,因为它是第一个被使用的。但要注意,这里的静态就是不能是final的,否则初始化不会执行。

我们在main方法中添加一个语句,如下
[java] view plaincopy
public static void main(String[] args) { 
       System.out.println(Derived.e); 
       new Derived().display(); 
    } 

好, 这下看一下这个执行结果,能过这个,我主要 是想证明,类的初始化是只执行一次呢还是每次主动使用类时都执行。。

通过这个截图我们可以看到,我们添加了一条语句 ,但输出结果只添加了两行,调用Derived类的实例的display()方法只是执行了方法中的语句 ,并没有再执行初始化语句,因此我们可以总结出,一个类只有会被初始化一次,除非是它被重新装载。

Last but not least,让我们看一下静态嵌套类的初始化情况,它是要被主动使用的时候才初始化呢,还是它的外围类被主动使用的时候 它就会被初始化呢?
为了方便,我们就在Demo类中添加一个静态嵌套类Inner,如下
[java] view plaincopy
public class Demo { 
    static int f; 
    static { 
       f = 100; 
       System.out.println("Demo:static init block invoked..and f=" + f); 
    } 
    
    static class Inner{ 
       static int g ; 
       static{ 
           g=666; 
           System.out.println("Inner:static init block invoked..and g="+g); 
       } 
    } 
  
    public static void main(String[] args) { 
       
    } 


看下main执行的结果:

我们可以看到,Inner类的静态初始化块并没有被执行,也就是说它并没有被初始化。好,现在在main函数中加上下面这句再看下执行结果:
[java] view plaincopy
System.out.println(Inner.g); 

看截图:

这下,很明显,Inner的初始化进行了,所以说,它与外围类没有必然的联系,外围类的初始化并不能导致它被初始化, 要初始化静态嵌套类必须主动使用它,而主动使用其外围类并不等同于主动使用Static Nested Class.

好,上面就是我所知道的关于类的初始化的东西了,如果有错误的地方还请高手指点,我及时修改。。



由此可知当新建一java对象(上面main方法中new B())时,它的内部初始化顺序为:
1.  父类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
2.  子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
3.  父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
4.  父类构造方法
5.  子类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
6.  子类构造方法
分享到:
评论

相关推荐

    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