`
cantellow
  • 浏览: 847325 次
  • 性别: Icon_minigender_1
  • 来自: 草帽海贼团
社区版块
存档分类
最新评论

初始化及类的加载

    博客分类:
  • Java
阅读更多

学习Java说难也不难,说容易也不容易,一个HelloWorld看起来简单,但是你清楚java背后是怎样加载类和初始化的吗?那些深入Java虚拟机的原理暂且不说,但至少有些流程你还是有必要搞清楚的。

每个类都是一个编译单元,应用程序的入口就是编译单元的main函数,因为它是static的,可以直接由类名来调用,不要把main想得太神奇,它也就只是一个方法,可以在main函数里再调用别个类的main函数,main函数也可以抛异常等等。。但是操作系统在调用main函数之前也必须先查找这个类然后将其加载。我们这里就假设一般的情况,有个名为Dog的类:

---类的加载---

1.当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者当Dog类的静态方法/静态字段首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。

2.如果Dog是一个导出类,那么编译器注意到它有一个基类(这是由关键字extends得知的),于是它继续进行加载基类(只是加载基类,这里还并没有初始化任何东西),不管你是否打算产生一个该基类的对象,这都要发生。如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推。直到它所有的基类都被加载。

3.接下来,根基类中的static初始化即会被执行,然后是下一个导出类的static被初始化,以此类推,这个过程中,有关静态初始化的所有动作都会执行,因此,静态初始化只在class对象首次加载的时候进行一次。

4.当Dog中的static也初始化后,那么就在堆上为Dog对象分配足够的存储空间,这一步和下面的步骤都是在要求创建对象的前提下才涉及的,有只加载类但是不创建此类对象的情况,比如当Dog类的静态方法/静态字段首次被访问时,Java就只加载类并初始化其中的静态字段,但是并不分配空间创建此类的对象。

---对象的实例化---

5.在给对象分配存储空间之后,这块存储空间首先被清零,即在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零,这就是为什么类的成员有默认值。

6.然后开始初始化基类的字段。

7.然后开始初始化基类的构造器。

8.最后是执行Dog类字段处的初始化动作。

9.然后是执行Dog的构造器。

成员变量初始化是在父类构造函数调用完后,在此之前,成员变量的值均是默认值。

在前三部一般都没有什么问题,但是后面一旦涉及构造器就很容易出现问题,因为构造器这个东西很特殊,这里简要说明一些要注意的地方:

在构造器中,如果为this添加了参数列表,那么就有了不同的含义,这将产生对符合此参数列表的某个构造器的明确调用,这样,就成了在构造器中调用构造器。而且一个构造器中只能调用另一个构造器,不能调用两个或以上。此外,必须将基类的构造器或this这样调用同类中其他构造器放在构造器的最起始处,否则,编译器会报错。(知道这是为什么吗?从概念上讲,“初始化”与“创建”是彼此独立的,但是在Java中,它们是被捆绑在一起的,这是为了安全。所以保证在被初始化之前不能有任何其他的操作。)

当涉及多态方法行为时,就更应该注意了,考虑下面一段代码:

abstract class Glyph

{

    abstract void draw();

    Glyph(){draw();}

}

class RoundGlyph extends Glyph

{

    private int radius = 1;

    RoundGlyph(int r){radius = r;}

    void draw(){System.out.println(radius);}

}

 

如果在main函数里调用:new RoundGlyph(5);

你以为draw()输出会是1吗?不是的,是0。因为在基类Glyph构造器中调用的 void draw()其实是RoundGlyph对象调用的,它调用的不是Glyph的draw()方法而是调用的RoundGlyph的draw()方法,而RoundGlyph的draw()方法它是把radius输出,而在这个时候,radius还没初始化。它只是在之前被置为0,所以输出的是0。有趣吧?涉及构造器还有很多有趣的东西,我就不一一列出了~~

分享到:
评论
2 楼 该用户名已经存在 2011-11-23  
C_J 写道
"它调用的不是Glyph的draw()方法而是调用的RoundGlyph的draw()方法"

那是因为draw()方法为虚拟的...

之所以是0,是因为语言的构造顺序问题这里的父类的construct优先与子类

比较赞同这个观点,不过关于draw()方法的问题感觉你们都没有说清楚!
1 楼 C_J 2009-11-07  
"它调用的不是Glyph的draw()方法而是调用的RoundGlyph的draw()方法"

那是因为draw()方法为虚拟的...

之所以是0,是因为语言的构造顺序问题这里的父类的construct优先与子类

相关推荐

    全局变量初始化导致的dll加载失败工程

    标题中的“全局变量初始化导致的dll加载失败工程”是一个典型的C++编程问题,涉及到动态链接库(DLL)的加载机制以及全局变量的初始化顺序。在C++编程中,全局变量的初始化顺序是一个需要深入理解的概念,尤其是在...

    解析Java虚拟机中类的初始化及加载器的父委托机制共14页

    Java虚拟机(JVM)是Java程序运行的核心,它的内部机制包括了类的加载、链接、初始化等关键过程。在Java编程中,了解这些过程对于优化程序性能、理解和解决类加载问题至关重要。本文将深入探讨Java虚拟机中的类初始...

    Java虚拟机JVM类加载初始化

    Java虚拟机JVM类加载初始化是Java程序运行过程中的关键环节,它负责将类的字节码文件加载到内存中并进行相应的处理,以便程序能够正确执行。在Java中,类加载器(Classloader)扮演着核心角色。下面将详细讨论类加载...

    Java类加载器:静态变量初始化.docx

    Java 类加载器静态变量初始化机制详解 Java 类加载器是 Java 语言的核心组件之一,负责将 Java 字节码文件加载到内存中,以便 JVM 可以执行它们。在 Java 中,类加载器是通过委派机制来实现的,即一个类加载器可以...

    探究java的ClassLoader及类变量初始化顺序

    需要注意的是,静态初始化块只在类被加载时执行一次,而实例初始化块(构造函数)则会在每次创建类的实例时执行。静态变量的初始化是在类加载时完成的,而实例变量的初始化则在对象创建时进行。 在实际开发中,对...

    C++全局变量初始化的一点总结

    静态初始化发生在程序加载时,主要针对那些可以用常量表达的初始化,例如零初始化(zero initialization)和常量初始化(const initialization)。零初始化的变量通常存放在BSS段,而常量初始化的变量则位于数据段,...

    java程序初始化顺序

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

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

    此外,静态初始化块只在类加载时执行一次,而初始化块(也称为实例初始化块)会在每次创建类的新实例时执行。这意味着静态成员和静态初始化块对于所有类的实例都是共享的,而实例成员和实例初始化块则是每个对象独有...

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

    这两种初始化块在创建类实例或加载类时分别扮演着不同的角色。 **静态初始化块** 静态初始化块是以`static`关键字标识的代码块,它在类被加载到Java虚拟机(JVM)时执行,且只执行一次。静态初始化块常用于设置类...

    详解Spring 中如何控制2个bean中的初始化顺序

    例如,假设我们有 2 个 bean A 和 B,B 加载的文件依赖 A 中加载的全局配置文件中的路径,所以需要 A 先于 B 初始化。此外,A 中的配置改变后也需要触发 B 的重新加载逻辑,所以 A 和 B 需要互相注入。 方案一:...

    java中类的初始化顺序

    3. **父类静态成员变量及初始化块**:如果当前类继承自另一个类,则父类的静态成员变量和静态初始化块会在子类之前被初始化。 4. **实例成员变量的默认初始化**:创建对象时,默认情况下,实例成员变量会被初始化为...

    深入java虚拟机加载初始化

    Java程序在运行过程中涉及几个关键的概念,包括类加载、连接以及初始化等阶段。 1. **类加载**(Load):这是类生命周期的第一个阶段,主要任务是将编译好的字节码文件(`.class`文件)加载到内存中。这个过程具体...

    java JVM 类加载-初始化 过程

    java JVM 类加载-初始化 过程

    Java类继承初始化顺序

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

    java代码的初始化顺序demo

    静态初始化块(也称为静态初始化器)是在类被加载并初始化时执行的,且只执行一次。它用于初始化类级别的静态变量。在`init`目录下的文件可能包含了不同静态初始化的示例。 3. **实例化阶段**: 当我们创建一个新...

    对象初始化流程梳理对象初始化流程梳理

    Java中的对象初始化流程是编程实践中一个非常重要的概念,它涉及到类加载、静态初始化块、实例初始化块、构造器等多个方面。下面将详细解释这个过程。 首先,对象初始化流程的起点是程序的入口点,即`main`方法。当...

    MFC中通用控件的初始化

    - `ICC_WIN95_CLASSES` 初始化所有Win95及以后版本的通用控件。 - `ICC_DATE_CLASSES` 初始化日期选择器、时间选择器等。 - `ICC_USEREX_CLASSES` 初始化组合框扩展控件。 - `ICC_COOL_CLASSES` 初始化酷栏(Rebar)...

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

    在Java虚拟机(JVM)中,类的初始化会在类加载和连接完成后发生。 初始化阶段的目标是确保类的静态成员被正确地初始化。有两种主要的方式进行类的初始化: 1. **静态变量的声明处赋值**:这是最直接的方式,如`...

Global site tag (gtag.js) - Google Analytics