面试的时候,经常会遇到这样的笔试题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和静态块,它们只包含一些简单的输出字符串到控制台的代码,然后让我们写出正确的输出结果。这实际上是在考察我们对于类的初始化知识的了解。

首先,我们先看看下面的代码,这就是很经典的考察方式。

  1. public class InitField {
  2. public static void main(String[] args) {
  3. SuperInitField p = new SuperInitField();
  4. SuperInitField c = new SubInitField();
  5. }
  6. }
  7. class SuperInitField {
  8. public SuperInitField() {
  9. System.out.println("parent");
  10. }
  11. static {
  12. System.out.println("static parent");
  13. }
  14. }
  15. class SubInitField extends SuperInitField {
  16. public SubInitField() {
  17. System.out.println("child");
  18. }
  19. static {
  20. System.out.println("static child");
  21. }
  22. }

不管你是否能很快速的写出正确的答案,我们先把这个程序放一边,了解一下Java虚拟机初始化的原理。

JVM通过加装、连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用。类型的生命周期如下图所示:

装载和连接必须在初始化之前就要完成。

类初始化阶段,主要是为类变量赋予正确的初始值。这里的“正确”初始值指的是程序员希望这个类变量所具备的起始值。一个正确的初始值是通过类变量初始化语句或者静态初始化语句给出的。初始化一个类包含两个步骤:

1) 如果类存在直接超类的话,且直接超类还没有被初始化,就先初始化直接超类。

2) 如果类存在一个类初始化方法,就执行此方法。

那什么时候类会进行初始化呢?Java 虚拟机规范为类的初始化时机做了严格定义:在首次主动使用时初始化。

那哪些情形才符合首次主动使用的标准呢?Java虚拟机规范对此作出了说明,他们分别是:

1) 创建类的新实例;

2) 调用类的静态方法;

3) 操作类或接口的静态字段(final字段除外);

4) 调用Java的特定的反射方法;

5) 初始化一个类的子类;

6) 指定一个类作为Java虚拟机启动时的初始化类。

除了以上六种情形以外,所有其它的方式都是被动使用的,不会导致类的初始化。

一旦一个类被装载、连接和初始化,它就随时可以使用了。现在我们来关注对象的实例化,对象实例化和初始化是就是对象生命的起始阶段的活动。

Java编译器为它编译的每个类都至少生成一个实例初始化方法,即<init>()方法。源代码中的每一个类的构造方法都有一个相对应的<init>()方法。如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器。

一个<init>()方法内包括的代码内容可能有三种:调用另一个<init>() 方法;对实例变量初始化;构造方法体的代码。
如果构造方法是明确地从调用同一个类中的另一个构造方法开始,那它对应的 <init>() 方法体内包括的内容为:

  1. 一个对本类的<init>()方法的调用;
  2. 实现了对应构造方法的方法体的字节码。

如果构造方法不是通过调用自身类的其它构造方法开始,并且该对象不是 Object 对象,那 <init>() 法内则包括的内容为:

  1. 一个父类的<init>()方法的调用;
  2. 任意实例变量初始化方法的字节码;
  3. 实现了对应构造方法的方法体的字节码。

通过上面的讲解是不是对你理解Java类型的初始化有一定的帮助呢?

好,那我们再来分析一下开始的那段代码:

  1. SuperInitField p = new SuperInitField();
  2. //SuperInitField的超类是Object
  3. //创建SuperInitField对象,属于首次主动使用,因此要先初始化Object类,然后再调用SuperInitField类变量初始化语句或者静态初始化语句,所以要输出static parent
  4. //类被装载、连接和初始化之后,创建一个对象,因此需要首先调用了Object的默认构造方法,然后再调用自己的构造方法,所以要输出parent
  5. SuperInitField c = new SubInitField();
  6. //SubInitField继承自SuperInitField
  7. //创建SubInitField对象,属于首次主动使用,父类SuperInitField已被初始化,因此只要调用SubInitField类变量初始化语句或者静态初始化语句,所以要输出static child
  8. //类被装载、连接和初始化之后,创建一个对象,因此需要首先调用了SuperInitField的构造方法,然后再调用自己的构造方法,所以要输出parent,然后再输出child

到现在你应该大体了解了Java类初始化的原理了吧,那我就留一到练习题吧,写出下列代码的运行结果。

  1. public class Test {
  2. public Test(){
  3. System.out.println("parent");
  4. }
  5. static{
  6. System.out.println("static parent");
  7. }
  8. public static void main(String[] args) {
  9. System.out.println("main");
  10. }
  11. }

这道题是关于初始化顺序的,已经有人写过这方面的文章了,我就不多说了

转载于:https://www.cnblogs.com/wslcs/p/4878687.html

Java 类与对象的初始化相关推荐

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

    跳转到主要内容 中国 [ 选择 ] dW 全部内容--------------  AIX and UNIX  Info Mgmt  Lotus  Rational  WebSphere-------- ...

  2. Java类和对象的初始化顺序

    本文摘录于http://blog.csdn.net/socoolfj/archive/2006/05/23/750425.aspx,并修改例子的代码,加上自己的见解. 类装载步骤 在Java中,类装载 ...

  3. 解析 Java 类和对象的初始化过程 由一个单态模式引出的问题谈起

    在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 问题引入 近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码 ...

  4. 解析 Java 类和对象的初始化过程(zhuang张 国建 (guojian.zhang@gmail

    [url]http://www.blogjava.net/rendong/default.html?page=2[/url]

  5. 杨校老师课堂之Java类与对象、封装、构造方法

    杨校老师课堂之Java类与对象.封装.构造方法 本篇文章内容如下: 面向对象 类与对象 三大特征--封装 构造方法 教学目标 能够理解面向对象的思想 能够明确类与对象关系 能够掌握类的定义格式 能够掌 ...

  6. 从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的?

    转载自   从Java类到对象的创建过程都做了些啥?内存中的对象是啥样的? 先回顾一下Java程序执行的过程: Java程序执行时,第一步系统创建虚拟机进程,然后虚拟器用类加载器Class Loade ...

  7. 【Java类和对象】

    Java类和对象 在Java简介中就有介绍到,Java是一门面向对象的编程语言,在面向对象的编程语言中,肯定离不开对象这个概念,而对象则是类的实例,所以也肯定离不开类这个概念.简单的来说就是,在Jav ...

  8. java类和对象在内存的表现形式

    Java内存分配与管理是Java的核心技术之一,不管学习任何一门语言,我们要知其然,知其所以然,本文主要分析下Java中类和对象在内存中的表现形式,方便我们对其有更深了解.一般Java在内存分配时会涉 ...

  9. Java类和对象小结

    java类与对象小结 类与对象 方法 对应的引用 属性:字段:成员变量 对象的创建和使用 类 1.类与对象 类是一个模板,抽象 对象是一个具体的实例 2.方法 存在于类中,类.方法名调用 3.对应的引 ...

  10. JAVA类和对象(1)

    JAVA类和对象 1.类和对象的初步认识 2.类的实例化 3.类的成员 3.1 字段/属性/成员变量 3.2 null 3.3 引用的指向 3.3 方法 (method) 3.4 static关键字 ...

最新文章

  1. c++ 绘制函数图像_【图像增强】CLAHE 限制对比度自适应直方图均衡化
  2. eclipse与SVN 结合(删除SVN中已经上传的问题)
  3. (第7篇)灵活易用易维护的hadoop数据仓库工具——Hive
  4. java获取jsp 组件,利用Observer模式解决组件间通信问题-JSP教程,Java技巧及代码
  5. LeetCode Unique Binary Search Trees(dp)
  6. 计算机应用基础2010一级,2010年一级结构基础辅导:(计算机应用基础)备考讲义(10)...
  7. [Swift]LeetCode498. 对角线遍历 | Diagonal Traverse
  8. flowable activiti 回退 驳回_驳回复审中图文组合商标与图形商标不近似性如何论述?...
  9. C++11 auto类型说明符
  10. java数组包含某个值_如何检查Java数组是否包含值?
  11. java连接Neo4j服务器
  12. torch.utils.data.Dataset用法
  13. linux 恢复member1账户,Linux操作系统第9讲 帐户管理和权限管理.ppt
  14. python --opencv图像处理轮廓(寻找轮廓、绘制轮廓)详解
  15. CVPR 2021 预讲 · 华为诺亚专场,5 篇精华报告,覆盖NAS、蒸馏、检测和降噪
  16. 计算机视觉行业博客和代码汇总
  17. 解决 3 errors and 0 warnings potentially fixable with the `--fix` option.问题
  18. 转!!以太网方案设计
  19. 时间戳90K是什么意思?
  20. tolua wrap原理与使用

热门文章

  1. 开源html5游戏-少年行
  2. CAS在Tomcat中实现单点登录
  3. iMazing for mac中文版苹果iOS设备管理器(已更新至v2.9.12版本)
  4. 使用HTML编写简单的邮件模版
  5. 超全面的权限系统设计方案!(万能通用)
  6. 知乎高赞:当update修改数据与原数据相同时会再次执行吗?
  7. 你们要的Windows IDEA 快捷键终极大全,速度收藏!
  8. 重磅!!Redis 6.0.0 已发布,有史以来改变最大的版本
  9. 去宇宙条面试被问:HashMap 为什么线程不安全?
  10. 微盟数据已经全面找回 并公布商家赔付计划