故事背景

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

让我们来看看吧

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. 并发知识(2)——关于Thread

    一些容易混淆的知识点 sleep vs wait sleep是Thread,wait是Object方法 wait和notify只能在同步代码块中调用 wait释放锁资源,sleep不释放锁资源 唤醒条 ...

  2. 利用ImageAI库只需几行python代码超简实现目标检测

    目录 什么是目标检测 目标检测算法 Two Stages One Stage python实现 依赖 安装 使用 附录 什么是目标检测 目标检测关注图像中特定的物体目标,需要同时解决解决定位(loca ...

  3. 前端插件之Datatables使用--上篇

    工欲善其事,必先利其器 本系列文章介绍我在运维系统开发过程中用到的那些顺手的前端插件,前边两篇分别介绍了Duallistbox插件和Select2插件的使用,这一篇开始Databases的征服之旅 D ...

  4. 统一流控服务开源:基于.Net Core的流控服务

    先前有一篇博文,梳理了流控服务的场景.业界做法和常用算法 统一流控服务开源-1:场景&业界做法&算法篇 最近完成了流控服务的开发,并在生产系统进行了大半年的验证,稳定可靠.今天整理一下 ...

  5. 动态SQL查询

    if+where: 用于查询操作,where标签可以智能判断是否添加and.or.where关键词 示例: <select id="findByParam" resultTy ...

  6. 手写Struts,带你深入源码中心解析

    个人剖析,不喜勿喷 扫码关注公众号,不定期更新干活 在此申明本博文并非原创,原文:http://blog.csdn.net/lenotang/article/details/3336623,本文章是在 ...

  7. Top 10 顶级项目管理工具

    成功的项目都要归功于成功的项目管理.这些工具帮你踏上成功之旅! 项目管理是成功完成项目并使公司变得伟大的秘诀.不,这不是标题党(clickbait) -- 我已经看到两家软件公司(我在那里工作)因为项 ...

  8. NN入门,手把手教你用Numpy手撕NN(一)

    前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...

  9. mongo常用语法

    首先要能进入控制台,进不去自己解决. 基本操作: show users:显示用户 show dbs:显示数据库列表 use <db name> 切换/创建数据库 show collecti ...

  10. 运行所选代码生成器时出错:“值-1超出了可接受的[0,2147483647]范围。参数名称:value”

    在使用vs2019添加mvc控制器的时候 这已经是第二次遇到这个问题了.常言道,多喝热水,重启试试.有时候当应用工作不正常,重启也许能解决问题.但是程序员通常接触不到服务器系统权限.而运维人员和公司流 ...