大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台的代码,然后让我们判断输出的结果。这实际上是在考查我们对于继承情况下类的初始化顺序的了解。 



我们大家都知道,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序以此是(静态变量、静态初始化块)>(变量、初始化块)>构造器。我们也可以通过下面的测试代码来验证这一点: 

Java代码 

public class InitialOrderTest { 



// 静态变量 

public static String staticField = "静态变量"; 

// 变量 

public String field = "变量"; 



// 静态初始化块 

static { 

System.out.println(staticField); 

System.out.println("静态初始化块"); 





// 初始化块 



System.out.println(field); 

System.out.println("初始化块"); 





// 构造器 

public InitialOrderTest() { 

System.out.println("构造器"); 





public static void main(String[] args) { 

new InitialOrderTest(); 







运行以上代码,我们会得到如下的输出结果: 



静态变量 

静态初始化块 

变量 

初始化块 

构造器 



这与上文中说的完全符合。那么对于继承情况下又会怎样呢?我们仍然以一段测试代码来获取最终结果: 

Java代码 

class Parent { 

// 静态变量 

public static String p_StaticField = "父类--静态变量"; 

// 变量 

public String p_Field = "父类--变量"; 



// 静态初始化块 

static { 

System.out.println(p_StaticField); 

System.out.println("父类--静态初始化块"); 





// 初始化块 



System.out.println(p_Field); 

System.out.println("父类--初始化块"); 





// 构造器 

public Parent() { 

System.out.println("父类--构造器"); 







public class SubClass extends Parent { 

// 静态变量 

public static String s_StaticField = "子类--静态变量"; 

// 变量 

public String s_Field = "子类--变量"; 

// 静态初始化块 

static { 

System.out.println(s_StaticField); 

System.out.println("子类--静态初始化块"); 



// 初始化块 



System.out.println(s_Field); 

System.out.println("子类--初始化块"); 





// 构造器 

public SubClass() { 

System.out.println("子类--构造器"); 





// 程序入口 

public static void main(String[] args) { 

new SubClass(); 







运行一下上面的代码,结果马上呈现在我们的眼前: 



父类--静态变量 

父类--静态初始化块 

子类--静态变量 

子类--静态初始化块 

父类--变量 

父类--初始化块 

父类--构造器 

子类--变量 

子类--初始化块 

子类--构造器 



现在,结果已经不言自明了。大家可能会注意到一点,那就是,并不是父类完全初始化完毕后才进行子类的初始化,实际上子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。 



那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?实际上这取决于它们在类中出现的先后顺序。我们以静态变量和静态初始化块为例来进行说明。 



同样,我们还是写一个类来进行测试: 

Java代码 

public class TestOrder { 

// 静态变量 

public static TestA a = new TestA(); 



// 静态初始化块 

static { 

System.out.println("静态初始化块"); 





// 静态变量 

public static TestB b = new TestB(); 



public static void main(String[] args) { 

new TestOrder(); 







class TestA { 

public TestA() { 

System.out.println("Test--A"); 







class TestB { 

public TestB() { 

System.out.println("Test--B"); 







运行上面的代码,会得到如下的结果: 



Test--A 

静态初始化块 

Test--B 



大家可以随意改变变量a、变量b以及静态初始化块的前后位置,就会发现输出结果随着它们在类中出现的前后顺序而改变,这就说明静态变量和静态初始化块是依照他们在类中的定义顺序进行初始化的。同样,变量和初始化块也遵循这个规律。

了解了继承情况下类的初始化顺序之后,如何判断最终输出结果就迎刃而解了。

静态块与静态成员的初始化工作与实例化过程无关,实例化必须先执行静态块和静态成员,但并不代表实例化一定会执行静态块和静态成员。只有当实例化的对应的类为加载入虚拟机的时候,才会进行这种操作。有些时候执行静态块或者初始化静态成员不一定就是实例化该类对象才会进行的,例如调研该类的某静态成员或者静态方法,又例如该类的子类被实例化或者调用了静态成员或静态方法等。



还有实例化的实际顺序其实是(省略类初始化过程)

1、进入当前类构造方法。

2、进入父类构造方法递归直到java.lang.Object类构造方法。

3、执行java.lang.Object类构造方法,顺序依次为成员变量初始与初始化块(安装上下文顺序),对应调用的构造方法体。

4、执行java.lang.Object类的直接子类的构造函数,这个过程递归到当前类。

5、当前类执行顺序与前面java.lang.Object类相同。



构造方法的本质其实就是一个普通的无返回参数的名字叫做<init>的方法,不过虚拟机调用这个方法的指令与其它方法不同而已,它的调用指令与调用private方法的指令相同。

在虚拟机中存在三种方法的调用指令,这三种调用指令在效率上不同。

接口方法的指令调用,这种调用速度最慢。

普通类方法的调用指令,这种调用速度中等。

构造方法与私有方法调用指令,这种调用速度最快。

Java类的变量初始化顺序的更多相关文章

  1. Java 类成员的初始化顺序

    Java 类成员的初始化顺序 前言:开发中碰到一个Java文件中有很多的成员变量,包括静态和非静态的,还有很多的初始化方法,很好奇这些成员的初始化顺序,在这里作个研究.   1  无继承情况下的Jav ...

  2. Java类的成员初始化顺序

    Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...

  3. java类的成员初始化顺序和初始化块知识

    java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...

  4. Java静态方法,静态变量,初始化顺序

    1. 静态方法: 成员变量分为实例变量和静态变量.其中实例变量属于某一个具体的实例,必须在类实例化后才真正存在,不同的对象拥有不同的实例变量.而静态变量被该类所有的对象公有(相当于全局变量),不需要实 ...

  5. Java中类成员变量初始化顺序

    一. 定义处默认初始化vs构造函数中初始化 java中类成员变量支持在声明处初始化,也可以在构造函数中初始化,那么这两者有什么区别呢?看下面例子 public class FieldsInit { p ...

  6. java类中元素初始化顺序

    结论:对于静态变量.静态初始化块.变量.初始化块.构造器,它们的初始化顺序依次是(静态变量.静态初始化块)>(变量.初始化块)>构造器. public class Test4 { @Tes ...

  7. java类及实例初始化顺序

    1.静态变量.静态代码块初始化顺序级别一致,谁在前,就先初始化谁.从上而下初始化(只在类加载时,初始化一次) 2.非静态变量.非静态代码块初始化顺序级别一致,谁在前,就先初始化谁.从上而下初始化(只要 ...

  8. Java 类的成员初始化顺序

    做个简单笔录,就当是重温下基础知识. 1.先看代码: package com.test; public class Test { public static void main(String[] ar ...

  9. java类对象的初始化顺序

    在下面这个例子中,我们分别在父类和子类中测试了静态代码块.普通代码块.静态成员变量.普通成员变量.构造器.静态内部类. 一:代码块及变量测试 class Field{ public static St ...

随机推荐

  1. nginx关闭日志功能access_log关闭

    网上一堆错误示例,我就不吐槽了,未经验证的各种关闭配置.emmm.... 错误示例: error_log off ; access_log on; 以上这些会产生名字为 off/on 的日志文件... ...

  2. ios下按钮click事件点击穿透问题

    和app进行混合开发的时候,一个页面使用h5写的,按钮上绑定click事件会触发下面图片上的a链接导致跳转,页面如图 顶部是一个banner,分vr.视频.图片三部分,红框处的三个nav按钮绑定cli ...

  3. Vue框架之vuex的使用

    1.首先需要在你的项目目录下安装vuex 终端命令: 2.在全局组件中导入与声明vuex 3.创建store实例对象 let store = new Vuex.store({ state:{ }, m ...

  4. 昨天521表白失败,我想用Python分析一下...表白记录和聊天记录

    昨天跟喜欢的妹子表白了. 失败了!.下面是表白的聊天记录: (跟妹子已经认识一段时间) 我:灭嘤嘤,我喜欢你. 妹子:你干嘛? 我:今天520,跟你表白鸭. 妹子:那....有多喜欢? 我: 有很多很 ...

  5. python词云图之WordCloud

    1. 导入需要的包package import matplotlib.pyplot as plt from scipy.misc import imread from wordcloud import ...

  6. python字典添加元素和删除元素

    1. 添加字典元素 方法一:直接添加,给定键值对 #pycharm aa = {'人才':60,'英语':'english','adress':'here'} print(aa) # {'人才': 6 ...

  7. Tkinter关于新建窗口内Entry无法获取值(值全为空)的解决办法

    最近在做Python的课程作业,遇到一个问题,描述如下: 使用Python内置的Tkinter模块进行GUI编程 给一个按钮(或菜单)绑定事件,打开一个新窗口,新窗口内有Entry若干,通过textv ...

  8. flask中使用ajax 处理前端请求 弹框展示

    菜小鱼初次使用 ajax,想前端提交数据,后端处理后,将结果以弹框的形式展示,在网上查看了好多,不停的调试,终于调通了 html: <html> <head></head ...

  9. BZOJ3514 GERALD07加强版

    GERALD07 Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问 ...

  10. 文件读写(三)利用FileStream类操作字节数组byte[]、BinaryFormatter、内存流MemoryStream

    一.Stream类概述 在.NET Framework中,文件和流是有区别的.文件是存储在磁盘上的数据集,它具有名称和相应的路径.当打开一个文件并对其进行读/写时,该文件就称为流(stream).但是 ...