故事背景

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

让我们来看看吧

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(); private Cheese() {
produceTimes=new Date().getTime()-produceDate;
} public long produceTimes() {
return produceTimes;
} public static void main(String[] args) {
System.out.println("current time in day(from 1900:00:00) : "+new Date().getTime()/(1000*60*60*24L)); System.out.println("cheese had produces : "+ cheese.produceTimes()/(1000*60*60*24L) +" days"); }
}

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

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

这是怎么回事呢?

破案

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

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

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

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 为何设置为

new Date(119,8,1)

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

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

其中,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. 消息中间件-activemq入门(二)

    上一节我们了解了JMS规范并且知道了JMS规范的良好实现者-activemq.今天我们就去了解一下activemq的使用.另外我们应该抱着目的去学习,别忘了我们为什么要使用消息中间件:解耦系统之间的联 ...

  2. Day3 AntV/G2图表的组成

    简介 为了更好的使用G2进行数据可视化,我们需要先了解G2图表的组成及其相关概念. 完整的G2图表组成如下图所示:可以看出图表主要由axes(坐标轴axis的复数),tooltip(提示信息),gui ...

  3. 获取n月后的当前时间

    例如用户计算会员的到期日期时间 public static Date getMonthNextOrBeforeDate(int monthNum) { Date dNow = new Date(); ...

  4. 并发模型与IO模型梳理

    并发模型 常见的并发模型一般包括3类,基于线程与锁的内存共享模型,actor模型和CSP模型,其中尤以线程与锁的共享内存模型最为常见.由于go语言的兴起,CSP模型也越来越受关注.基于锁的共享内存模型 ...

  5. 用 Python 分析上网记录,发现了很多不可思议的事

    摘要:分享个​ Python 神工具.​ 长时间使用浏览器会积累大量浏览器历史记录,这些是很隐私的数据,里面甚至可能有一些不可描述的网站或者搜索记录不想让别人知道. 不过,我们自己可能会感兴趣,天天上 ...

  6. iView表格行验证问题

    iView Table 3.2.0 版本 需求: 验证前两行的姓名不能为空: 解决方案: 判断是否前两行,如是则增加校验规则: 需在<FormItem>前加<Form>标签否则 ...

  7. python之web自动化验证码识别解决方案

    验证码识别解决方案 对于web应用程序来讲,处于安全性考虑,在登录的时候,都会设置验证码,验证码的类型种类繁多,有图片中辨别数字字母的,有点击图片中指定的文字的,也有算术计算结果的,再复杂一点就是滑动 ...

  8. python所有的内置异常类型汇总

    内置异常基类 在 Python 中,所有异常必须为一个派生自 BaseException 的类的实例. 通过子类化创建的两个不相关异常类永远是不等效的,既使它们具有相同的名称. 下列异常主要被用作其他 ...

  9. 谈谈JVM垃圾回收

    概述 Java运行时区域中,程序计数器,虚拟机栈,本地方法栈三个区域随着线程的而生,随线程而死,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题.而Java堆和方法区则不一样,一个接口的 ...

  10. Springboot + Stopping service [Tomcat]+ Process finished with exit code 0

    在Springboot 的版本为: <version>1.5.10.RELEASE</version> 原因:代码中有非法格式的结构,及代码写错啦,例如: <result ...