故事背景

有一天,老鼠小白发现了一个奇怪的问题,它的奶酪的生产日期被谁搞丢了,不知道奶酪是否过期,可怎么吃呀?

让我们来看看吧

  1. import java.util.Date;
    public class Cheese {
    public static final Cheese cheese=new Cheese();
    private final long produceTimes;
    private static final long produceDate =new Date(119,8,1).getTime();
  2.  
  3. private Cheese() {
    produceTimes=new Date().getTime()-produceDate;
    }
  4.  
  5. public long produceTimes() {
    return produceTimes;
    }
  6.  
  7. public static void main(String[] args) {
    System.out.println("current time in day(from 1900:00:00) : "+new Date().getTime()/(1000*60*60*24L));
  8.  
  9. System.out.println("cheese had produces : "+ cheese.produceTimes()/(1000*60*60*24L) +" days");
  10.  
  11. }
    }

按照小白的预期,程序该跑出奶酪上市了多少天,可是打印出的结果确实奶酪不会过期

  1. current time in day(from 1900:00:00) : 18153
    cheese had produces : 18153 days

这是怎么回事呢?

破案

查看代码提交记录,发现老鼠小蓝有修改记录,仅仅调整了两行程序的顺序,小白原来的代码如下:

  1. import java.util.Date;
    public class Cheese {
  2.  
  3. private final long produceTimes;
    private static final long produceDate =new Date(119,8,1).getTime();
    public static final Cheese cheese=new Cheese();
  4.  
  5. private Cheese() {
    produceTimes=new Date().getTime()-produceDate;
    }
  6.  
  7. public long produceTimes() {
    return produceTimes;
    }
  8.  
  9. public static void main(String[] args) {
    System.out.println("current time in day(from 1900:00:00) : "+new Date().getTime()/(1000*60*60*24L));
  10.  
  11. System.out.println("cheese had produces : "+ cheese.produceTimes()/(1000*60*60*24L) +" days");
  12.  
  13. }
    }

仅仅修改了两个变量的顺序,输出的结果就大相径庭了

  1. current time in day(from 1900:00:00) : 18153
    cheese had produces : 13 days

这才是小白鼠想要的结果!

于是小白鼠去请教java的创造者java之父

原来,实例的初始化也是有讲究的。

1.static字段先设置默认值,其中cheese被设置为null,produceDate被设置为0

2.然后static初始器执行,按照声明出现的顺序执行:

如果先执行cheese的话,调用Cheese()构造方法,此时用produceDate=0为值。

如果先执行produceDate的话,producteDate被设置为2019-09-01,再调用cheese()构造方法。

3 最后从构造器返回cheese类的初始化。

说明

Date设置日期为2019-09-01 为何设置为

  1. new Date(119,8,1)

大家可以进去源码看说明情况

  1. /**
  2. * Allocates a <code>Date</code> object and initializes it so that
  3. * it represents midnight, local time, at the beginning of the day
  4. * specified by the <code>year</code>, <code>month</code>, and
  5. * <code>date</code> arguments.
  6. *
  7. * @param year the year minus 1900.
  8. * @param month the month between 0-11.
  9. * @param date the day of the month between 1-31.
  10. * @see java.util.Calendar
  11. * @deprecated As of JDK version 1.1,
  12. * replaced by <code>Calendar.set(year + 1900, month, date)</code>
  13. * or <code>GregorianCalendar(year + 1900, month, date)</code>.
  14. */
  15. @Deprecated
  16. public Date(int year, int month, int date) {
  17. this(year, month, date, 0, 0, 0);
  18. }

其中,year份是从1900年开始的年数,即2019-1900=119

month是0~11计数的,需要实际月份减1,即9-1=8

date 是1~31计数的,实际天就可以 即1

参考资料

【1】https://docs.oracle.com/javase/specs/jls/se12/html/jls-12.html#jls-12.4

谁动了我的奶酪?--java实例初始化的顺序问题的更多相关文章

  1. Java程序初始化的顺序

    Java程序初始化的顺序 java程序初始化工作可以在许多不同的代码块中来完成(例如:静态代码块.构造函数等),他们执行的顺序如下: 父类静态变量 父类静态代码块 子类静态变量 子类静态代码块 父类非 ...

  2. Java类、实例初始化的顺序

    求如下 java 代码的输出?? class T implements Cloneable{ public static int k = 0; public static T t1 = new T(& ...

  3. 什么是Java实例初始化块

    在本篇文章,我将会使用一个例子展示什么是实例变量初始化块,实例初始化块和静态初始化块,然后说明在Java中实例初始化块是如何工作的. 执行顺序 查看下面的代码,你知道哪个先执行吗? package s ...

  4. 《Java程序员面试笔试宝典》之Java程序初始化的顺序是怎样的

    在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下三原则优 ...

  5. Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)

    1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...

  6. 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的

    在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象.    Java程序的初始化一般遵循以下三个原则(以下 ...

  7. java实例初始化块

    实例初始化程序块用于初始化实例数据成员. 它在每次创建类的对象时运行.实例变量的初始化可以是直接的,但是可以在初始化实例初始化块中的实例变量时执行额外的操作. 什么是实例初始化块的使用,我们可以直接分 ...

  8. 八、 Java程序初始化的顺序(一)

    今天在写构造器方法的时候,遇到了一个小问题,由这个问题引发了一连串的思考,在一个Java类中变量与类的初始化执行顺序是什么样的呢?## 发现问题 class Student{ private Stri ...

  9. 九、 Java程序初始化的顺序(二)

    之前的一篇博客里我写了关于在一个类中的程序初始化顺序,但是在Java的面向对象里,类之间还存在着继承的关系.所以关于程序的初始化顺序,我们可以再细划分为:父类静态变量,父类的静态代码块,父类构造器,父 ...

随机推荐

  1. 数据结构之堆栈java版

    import java.lang.reflect.Array; /* 具体原理在c++版已经说的很清楚,这里不再赘述, 就提一点:java的泛型具有边界效应,一旦离开作用域立马被替换为object类型 ...

  2. 11个rsync使用实例

    rsync表示 remote sync,其用于在本地或与远程主机间进行文件或目录备份.相比较scp等工具,rsync有以下优点: 速度:除首次全拷贝外,其他时候实现增量拷贝,加快传输速度 安全:传输数 ...

  3. OpenResty 社区王院生:APISIX 的高性能实践

    2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,OpenResty 软件基金会联合创始人王院生在活动上做了&l ...

  4. ansible之数据提取与Juniper实例演示

    一.Ansible列表两种表达方式 基于YAML的列表 my_list: - a - b - c - d 基于Json格式的列表 {"my_list":[ "a" ...

  5. React引入AntD按需加载报错

    背景:React使用create-react-app脚手架创建,然后yarn run eject暴露了配置之后修改less配置, 需求:实现antd组件按需加载与修改主题. 一开始是按照webpack ...

  6. Asp.NetCore源码学习[1-2]:配置[Option]

    Asp.NetCore源码学习[1-2]:配置[Option] 在上一篇文章中,我们知道了可以通过IConfiguration访问到注入的ConfigurationRoot,但是这样只能通过索引器IC ...

  7. 使用 Docker Compose 快速构建 TiDB 集群

    本文档介绍如何在单机上通过 Docker Compose 快速一键部署一套 TiDB 测试集群.Docker Compose 可以通过一个 YAML 文件定义多个容器的应用服务,然后一键启动或停止. ...

  8. 使用Eclipse开发动态Javaweb项目

    使用Eclipse开发动态Javaweb项目 一.Eclipse的使用 1. 把开发选项切换到 JavaEE 2. 可以在 Window -> Show View 中找到 Package Exp ...

  9. linux 网络基础之IP地址

    IP是英文Internet Protocol的缩写,意思是“网络之间互连的协议”,也就是为计算机网络相互连接进行通信而设计的协议. IP地址类型分为:公有地址.私有地址. 公有地址 公有地址(Publ ...

  10. 【欧拉降幂】Super_log

    In Complexity theory, some functions are nearly O(1)O(1), but it is greater then O(1)O(1). For examp ...