`

类、对象初始化顺序

F# 
阅读更多
初始化(initialization)其实包含两部分:
1.类的初始化(initialization class & interface)
2.对象的创建(creation of new class instances)。
因为类的初始化其实是类加载(loading of classes)的最后一步,所以很多书中把它归结为“对象的创建”的第一步。其实只是看问题的角度不同而已。为了更清楚的理解,这里还是分开来。
顺序:
应为类的加载肯定是第一步的,所以类的初始化在前。大体的初始化顺序是:
类初始化 -> 子类构造函数 -> 父类构造函数 -> 实例化成员变量 -> 继续执行子类构造函数的语句
下面结合例子,具体解释一下。
1。类的初始化(Initialization classes and interfaces),其实很简单,具体来说有:
(a)初始化类(initialization of class),是指初始化static field 和执行static初始化块。
例如:
class Super {
        static String s = “initialization static field”; //初始化static field,其中“= “initialization static field” ”又叫做static field initializer
        // static初始化块,又叫做static initializer,或 static initialization block
        static {
        System.out.println(“This is static initializer”);
}
}
btw,有些书上提到static initializer 和 static field initializer 的概念,与之对应的还有 instance initializer 和 instance variable initializer。例子中的注释已经解释了其含义。
(b)初始化接口(initialization of interface),是指初始化定义在该interface中的field。
*注意*
--initialization classes 时,该class的superclass 将首先被初始化,但其实现的interface则不会被初始化。
--initialization classes 时,该class的superclass,以及superlcass的superclass 会首先被递归地初始化,从java.lang.Object一直到该class为止。但initialiazation interface的时候,却不需如此,只会初始化该interface本身。
--对于由引用类变量(class field)所引发的初始化,只会初始化真正定义该field的class。
--如果一个static field是编译时常量(compile-time constant)(即定义为static final field),则对它的引用不会引起定义它的类的初始化。
为了帮助理解最后两点,请试试看下面的例子:
public class Initialization {
       
        public static void main(String[] args) {
               
                System.out.println(Sub.x); // Won't cause initialization of Sub, because x is declared by Super, not Sub.
                                         // 不会引起Sub类的初始化,因为x是定义在Super类中的
                System.out.println("-------------------------");
                System.out.println(Sub.y); // Won't cause initialization of Sub, because y is constant.
                                         // 不会引起Sub类的初始化,因为y是常量
                System.out.println("-------------------------");
                System.out.println(Sub.z = 2004); // Will cause initialization of Sub class
  // 将会引起Sub的初始化
  }
}
class Super{
        static int x = 2006;
}
class Sub extends Super {
       
        static final int y = 2005;
       
static int z;
       
static {
                System.out.println("Initialization Sub");
        }
}
2。对象的创建(creation of new class instances),稍微有点烦琐,具体的步骤如下
(a) 所有的成员变量—包括该类,及它的父类中的成员变量--被分配内存空间,并赋予默认值。(Btw,这里是第一次初始化成员变量)
(b) 为所调用的构造函数初始化其参数变量。(如果有参数)
(c) 如果在构造函数中用this 调用了同类中的其他构造函数,则按照步骤(b)~(f)去处理被调用到的构造函数。
(d) 如果在构造函数中用super调用了其父类的构造函数,则按照步骤(b)~(f)去处理被调用到的父类构造函数。
(e) 按照书写顺序,执行instance initializer 和 instance variable initializer来初始化成员变量。(Btw,这里是第二次初始化成员变量)
(f) 按照书写顺序,执行constructor的其余部分。
*注意*
成员变量其实都被初始化2次,第一次是赋予默认值,第二次才是你想要设定的值。
最后看一个例子:
public class InitializationOrder {
        public static void main(String[] args) {
                Subclass sb = new Subclass();
        }
}
class Super{
       
        static {
                System.out.println(1);
        }
       
        Super(int i){
                System.out.println(i);
        }
}
class Subclass extends Super implements Interface{
       
        static {
                System.out.println(2);
        }       
       
        Super su = new Super(4);
       
        Subclass() {
                super(3);
                new Super(5);
        }
}
interface Interface{
        static Super su = new Super(0);
}
稍微解释一下:
首先,Java虚拟机要执行InitializationOrder类中的static 方法main(),这引起了类的初始化。开始初始化InitializationOrder类。具体的步骤略去不说。
接着,InitializationOrder类初始化完毕后,开始执行main()方法。语句Subclass sb = new Subclass()将创建一个Subclass对象。加载类Subclass后对其进行类初始化,但因为Subclass有一个父类Super,所以先初始化Super类,初始化块static {System.out.println(1);}被执行,打印输出1;
第三,Super初始化完毕后,开始初始化Subclass类。static {System.out.println(2);}被执行,打印输出2;
第四,至此,类的加载工作全部完成。开始进入创建Subclass的对象过程。先为Subclass类和其父类Super类分配内存空间,这时Super su 被附值为null;
第五,执行构造函数Subclass()时,super(3)被执行。如前面(d)所说,Super类的构造函数Super(int i){….}被调用,并按照步骤(b)~(f)来处理。因此,递归调用Super类的父类Object类的构造函数,并按照步骤(b)~(f)来初始化Object类,不过没有任何输入结果。最后打印输出3;
第六,如前面(e)所说,初始化成员变量su,其结果是打印输出4;
第七,如前面(f)所说,执行new Super(5),并打印输出5;
最后,Subclass虽然实现了接口Interface,但是初始化它的时候并不会引起接口的初始化,所以接口Interface中的static Super su = new Super(0)自始至终都没有被执行到。
max做的小改动:
public class Test {
    public static void main(String[] args) {
            Subclass sb = new Subclass();
    }
}
class SS{
 public SS(int i){
  System.out.println(i);
 }
}
class Super{
   
    static {
            System.out.println(1);
    }
    SS ss = new SS(100);
   
    Super(int i){
            System.out.println(i);
    }
}
class Subclass extends Super implements Interface{
   
    static {
            System.out.println(2);
    }       
   
    Super su = new Super(4);
   
    Subclass() {
            super(3);
            new Super(5);
    }
}
interface Interface{
    static Super su = new Super(0);
}
--------------------
结果为:
1
2
100
3
100
4
100
5
分享到:
评论

相关推荐

    类继承的初始化顺序类,继承的初始化顺序

    然而,在涉及到类继承时,一个重要的问题是类实例化时的初始化顺序。本篇文章将围绕“类继承的初始化顺序”这一主题展开,详细解析初始化过程中涉及的关键概念和技术细节。 ### 类继承的初始化顺序概述 在面向对象...

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

    在实际开发中,理解这个初始化顺序是非常重要的,尤其是在设计复杂的类结构或者涉及单例模式、线程安全初始化等场景时。如果在构造器或初始化块中依赖其他静态或非静态成员,必须确保这些成员在需要之前已经被正确...

    Java类继承初始化顺序

    当我们谈论“Java类继承初始化顺序”时,涉及到的关键知识点包括构造器、成员变量的初始化、super关键字以及方法的覆盖。 首先,了解类初始化的顺序至关重要。当创建一个子类实例时,初始化过程遵循以下步骤: 1. ...

    “礼让”原则学习Java对象初始化顺序.pdf

    "Java 对象初始化顺序学习指南" 在学习 Java 编程语言时,对象初始化顺序是一个非常重要的知识点,但是许多学生却感到困惑和困难。事实上,Java 对象初始化顺序并不难理解,只需要掌握“礼让”原则和 JVM 的执行...

    java类变量初始化顺序

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

    java中类的初始化顺序

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

    java程序初始化顺序

    以下是对Java程序初始化顺序的详细说明: 1. **类加载阶段**: - **加载**:当Java虚拟机(JVM)首次遇到一个类的引用时,会通过类加载器进行加载。加载过程包括找到类的.class文件,读取其字节码,并转化为内存中...

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

    同时,掌握类变量初始化顺序可以避免因误解而导致的错误,特别是在多线程环境中,对静态变量的并发访问和初始化顺序的控制需要特别注意。 总之,深入理解Java的ClassLoader机制和类变量初始化顺序是提升Java编程...

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

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

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

    在Java中,类的初始化顺序是一个经常被问及的面试题目,尤其对于Java程序员和工程师来说,了解这个知识点是必须的。在Java中,类的初始化顺序是面试中的经典问题之一,它涉及到继承、静态成员以及实例成员等多个方面...

    类初始化顺序示例讲解

    ### 类初始化顺序详解 本文将基于给定的Java示例代码深入探讨类初始化的顺序问题。这不仅是Java语言的关键特性之一,在其他面向对象语言(如C++、.NET)中也有相似的概念。理解这一概念有助于程序员更好地掌握面向...

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

    静态初始化块和对象初始化块的执行顺序不同。静态初始化块在类加载时执行,而对象初始化块在创建新对象时执行。它们可以相互配合,以实现更复杂的初始化逻辑。例如,静态初始化块可以用来设置全局配置,而对象初始化...

    java代码的初始化顺序demo

    总之,Java代码的初始化顺序是类加载的必然过程,涉及到静态和实例初始化块、构造函数、成员变量初始化以及继承关系的影响。这个demo是学习和理解这些概念的重要工具,通过实际操作可以加深对Java内存管理和对象生命...

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf,这是一份不错的文件

    JAVA 是一门面向对象的编程语言,类的初始化顺序是 JAVA 程序员和 JAVA 工程师面试中一个非常重要的知识点。本文将详细讲解类的初始化顺序,并提供了相关的测试代码,使读者能够更好地理解和掌握这个知识点。 在 ...

    Java初始化顺序1

    在上面的示例代码中,我们可以看到,类变量和实例变量的初始化顺序是按照定义的顺序进行的。同时,我们还可以看到,静态变量的初始化顺序是按照定义的顺序,并且只在第一次访问时初始化。 在 Java 中,static ...

    JAVA类的初始化顺序文.pdf

    总之,类的初始化顺序是:静态成员 -> 静态初始化块 -> 非静态成员 -> 非静态初始化块 -> 构造器。这个顺序同样适用于继承关系,只是会先初始化父类的部分,再初始化子类的部分。掌握这一知识能帮助程序员更好地设计...

    java对象的初始化顺序[参考].pdf

    Java对象的初始化顺序是一个关键的编程概念,它涉及到类加载、静态初始化、实例初始化等多个步骤。下面我们将详细探讨这些步骤。 首先,当程序运行并创建一个新的对象时,JVM(Java虚拟机)会按照特定的顺序来初始...

    Java中对象初始化顺序的详细介绍

    这种情况下,初始化顺序如下:首先,`Lower`类的实例创建并分配默认值,然后调用`Upper`的构造器,接着执行`Initializer.initialize()`,该方法根据对象的实际类型(`Lower`)来设置字段的值。 5. **默认值**:即使...

    JAVA面试题解惑系列(一)——类的初始化顺序-JAVA程序员JAVA工程师面试必看.pdf

    在Java编程世界中,类的初始化顺序是理解面向对象编程概念的一个重要方面。尤其对于那些准备应对技术面试的Java程序员和工程师来说,掌握这一知识点是面试时的必备能力之一。本文将深入探讨Java中类的初始化顺序,...

    JAVA面试题解惑系列类的初始化顺序JAVA程序员JAVA工程师面试必看.pdf

    Java语言中的类初始化顺序是面试中常见的问题,尤其对于Java程序员和工程师来说,理解这一概念至关重要。本篇文章将深入解析类初始化的顺序以及在继承情况下的表现。 首先,我们需要明确类初始化顺序的基本规则: ...

Global site tag (gtag.js) - Google Analytics