面试的时候,经常会遇到这样的笔试题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和静态块,它们只包含一些简单的输出字符串到控制台的代码,然后让我们写出正确的输出结果。这实际上是在考察我们对于类的初始化知识的了解。
首先,我们先看看下面的代码,这就是很经典的考察方式。
  • public class InitField {
  • public static void main(String[] args) {
  • SuperInitField p = new SuperInitField();
  • SuperInitField c = new SubInitField();
  • }
  • }
  • class SuperInitField {
  • public SuperInitField() {
  • System.out.println("parent");
  • }
  • static {
  • System.out.println("static parent");
  • }
  • }
  • class SubInitField extends SuperInitField {
  • public SubInitField() {
  • System.out.println("child");
  • }
  • static {
  • System.out.println("static child");
  • }
  • }
不管你是否能很快速的写出正确的答案,我们先把这个程序放一边,了解一下Java虚拟机初始化的原理。
JVM通过加装、连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用。类型的生命周期如下图所示:
装载和连接必须在初始化之前就要完成。
类初始化阶段,主要是为类变量赋予正确的初始值。这里的“正确”初始值指的是程序员希望这个类变量所具备的起始值。一个正确的初始值是通过类变量初始化语句或者静态初始化语句给出的。初始化一个类包含两个步骤:
1) 如果类存在直接超类的话,且直接超类还没有被初始化,就先初始化直接超类。
2) 如果类存在一个类初始化方法,就执行此方法。
那什么时候类会进行初始化呢?Java 虚拟机规范为类的初始化时机做了严格定义:在首次主动使用时初始化。
那哪些情形才符合首次主动使用的标准呢?Java虚拟机规范对此作出了说明,他们分别是:
1) 创建类的新实例;
2) 调用类的静态方法;
3) 操作类或接口的静态字段(final字段除外);
4) 调用Java的特定的反射方法;
5) 初始化一个类的子类;
6) 指定一个类作为Java虚拟机启动时的初始化类。
除了以上六种情形以外,所有其它的方式都是被动使用的,不会导致类的初始化。
一旦一个类被装载、连接和初始化,它就随时可以使用了。现在我们来关注对象的实例化,对象实例化和初始化是就是对象生命的起始阶段的活动。
Java编译器为它编译的每个类都至少生成一个实例初始化方法,即<init>()方法。源代码中的每一个类的构造方法都有一个相对应的<init>()方法。如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器。
一个<init>()方法内包括的代码内容可能有三种:调用另一个<init>() 方法;对实例变量初始化;构造方法体的代码。
如果构造方法是明确地从调用同一个类中的另一个构造方法开始,那它对应的 <init>() 方法体内包括的内容为:
  • 一个对本类的<init>()方法的调用;
  • 实现了对应构造方法的方法体的字节码。
如果构造方法不是通过调用自身类的其它构造方法开始,并且该对象不是 Object 对象,那 <init>() 法内则包括的内容为:
  • 一个父类的<init>()方法的调用;
  • 任意实例变量初始化方法的字节码;
  • 实现了对应构造方法的方法体的字节码。
通过上面的讲解是不是对你理解Java类型的初始化有一定的帮助呢?
好,那我们再来分析一下开始的那段代码:
  • SuperInitField p = new SuperInitField();
  • //SuperInitField的超类是Object
  • //创建SuperInitField对象,属于首次主动使用,因此要先初始化Object类,然后再调用SuperInitField类变量初始化语句或者静态初始化语句,所以要输出static parent
  • //类被装载、连接和初始化之后,创建一个对象,因此需要首先调用了Object的默认构造方法,然后再调用自己的构造方法,所以要输出parent
  • SuperInitField c = new SubInitField();
  • //SubInitField继承自SuperInitField
  • //创建SubInitField对象,属于首次主动使用,父类SuperInitField已被初始化,因此只要调用SubInitField类变量初始化语句或者静态初始化语句,所以要输出static child
  • //类被装载、连接和初始化之后,创建一个对象,因此需要首先调用了SuperInitField的构造方法,然后再调用自己的构造方法,所以要输出parent,然后再输出child
到现在你应该大体了解了Java类初始化的原理了吧,那我就留一到练习题吧,写出下列代码的运行结果。
    • public class Test {
    • public Test(){
    • System.out.println("parent");
    • }
    • static{
    • System.out.println("static parent");
    • }
    • public static void main(String[] args) {
    • System.out.println("main");
    • }
    • }

AJPFX总结Java 类与对象的初始化的更多相关文章

  1. 解析Java类和对象的初始化过程

    类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...

  2. [转载]解析 Java 类和对象的初始化过程

    原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-clobj-init/index.html 由一个单态模式引出的问题谈起 类的初始化和对象初始化 ...

  3. Java类和对象初始化

    类的生命周期: Java类的初始化: 本阶段负责为类变量赋正确的初始值.(类变量即静态变量) Java编译器把所有的类变量初始化语句和静态初始化器通通收集到<clinit>方法中,该方法只 ...

  4. Java基础——类和对象的初始化过程

    本节把类和对象的初始化所涉及到的所有代码块阐述一边. 示例代码: public class Demo { private static String name; private String age; ...

  5. [Java初探08]__简单学习Java类和对象

    前言 在前面的学习中,我们对面向对象的编程思想有了一个基本的了解,并且简单的了解了类和对象的定义.那么类和对象在Java语言中是如何表现的,这次,就从实际出发,学习一下一下类和对象在Java语言中的使 ...

  6. 【基础】java类的各种成员初始化顺序

    父子类继承时的静态代码块,普通代码块,静态方法,构造方法,等先后顺序 前言: 普通代码块:在方法或语句中出现的{}就称为普通代码块.普通代码块和一般的语句执行顺序由他们在代码中出现的次序决定--“先出 ...

  7. Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序

    先看一道Java面试题: public class Baset { private String baseName = "base"; // 构造方法 public Baset() ...

  8. java类和对象之间的差

    java类和对象之间的差别是一个普遍的问题,刚开始学习java当它来到与类和对象接触.今天就来总结一下它们之间的差异. 先说说class和object差异.事实上,词:object是全部class的父 ...

  9. 危险代码:如何使用Unsafe操作内存中的Java类和对象

    危险代码:如何使用Unsafe操作内存中的Java类和对象—Part1 危险代码:如何使用Unsafe操作内存中的Java类和对象—Part2 危险代码:如何使用Unsafe操作内存中的Java类和对 ...

随机推荐

  1. boost的内存管理

    smart_ptr raii ( Resource Acquisition Is Initialization ) 智能指针系列的都统称为smart_ptr.包含c++98标准的auto_ptr 智能 ...

  2. js的几种循环语句

    //js种的循环语句 //while与do while的区别是while是满足条件后才执行 //do while是不管满不满足条件都会执行一次 //for 循环与while,do while相比循环结 ...

  3. 【IOS】启动画面

    总述: 两种方式,一种是使用系统自带的.按规则定义启动图片名称就可以,显示为1秒,要想延长时间,用[nsthread ​ sleepForTimeInterval:5.0] ,还有一种就是自己定义ui ...

  4. NHibernate直接执行SQL进行插入

    有时候,需要用NHibernate直接执行SQL进行数据insert或update. 怎么写呢?简单一点的,可以直接拼凑出来的SQL,这样写: using NHibernate; StringBuil ...

  5. 用javascript写一个前端等待控件

    前端等待控件有啥新奇的?什么jquery啦,第三方控件啦,好多好多,信手拈来. 因为项目使用了bootstrap的原因,不想轻易使用第三方,怕不兼容.自己写一个. 技术点包括动态加载CSS,javas ...

  6. JavaScript的高大强

    1,JavaScript的引入方式 1.1>Script标签内写代码 <Script> //这里写JS代码的地方 </Script> 1.2>引入额外的JS文件 & ...

  7. Delphi的goto语法

    今天第一次主要到Delphi也有goto语法,特别是其奇怪的label声明.估计主要是用来跳出多重循环,而且还真有人使用这种方式.记个笔记: procedure TForm1.btn3Click(Se ...

  8. uboot中关于LCD的代码分析【转】

    本文转载自:http://blog.csdn.net/oqqHuTu12345678/article/details/72236117 以下内容源于朱有鹏<物联网大讲坛>课程的学习,如有侵 ...

  9. Jquery与Dom对象相互转化

    Jquery与Dom对象相互转化   jQurey对象和DOM对象的相互转换 在讨论jQurey对象和DOM对象的相互转换之前,我们先约定定义变量的风格.如果我们获取的对象是jQuery对象,那么我们 ...

  10. sqlserver游标使用误区

    在使用游标出现逻辑错误时,查阅资料,只有改掉while中的游标取值在while循环最后,没有说明while以前会出现的错误,而且没有具体说明原因,今天在工作中解决了这个问题,写了这个博客,希望对使用游 ...