HashMap匿名初始化和日期的时区问题

实际开发中遇到了一些奇怪的问题在这里记录下:

一、HashMap初始化

先来看段代码:

import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

 
public class Test  {

    public static void main(String[] args) {
        Map<String,Object> map  = new HashMap<String, Object>(){{
            put("key1","val1");
            put("key2","val2");
        }};
        String str = new Gson().toJson(map);
        System.out.println("str: "+str);
    }

}

输出:

str: null

 初始化HashMap时,这里的双括号到底什么意思代表什么呢?先来看段代码

public class Test {
 
 public Test() {
  System.out.println("Constructor called:构造器被调用");
 }
 static {
  System.out.println("Static block called:静态块被调用");
 }
 {
  System.out.println("Instance initializer called:实例初始化块被调用");
 }
 public static void main(String[] args) {
  new Test();
  System.out.println("=======================");
  new Test();
 }
}

输出:

 Static block called:静态块被调用
 Instance initializer called:实例初始化被调用
 Constructor called:构造器被调用
 =======================
 Instance initializer called:实例初始化被调用
 Constructor called:构造器被调用

也就是说第一层括弧实际是定义了一个匿名内部类 (Anonymous Inner Class),第二层括弧实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。
上面代码如果是写在 Test 类中,编译后你会看到会生成 Test$1.class 文件,反编译该文件内容:

import java.util.HashMap;
 
class Test$1 extends HashMap // 创建了一个 HashMap 的子类
 {
 Test$1()
 {    // 第二个 {} 中的代码放到了构造方法中去了 
     put("key1","val1");
     put("key2","val2");
 }
 }

匿名内部类写法的潜在问题
    文章开头提到的写法的好处很明显就是一目了然。这里来罗列下此种方法的坏处,如果这个对象要串行化,可能会导致串行化失败。
  1.此种方式是匿名内部类的声明方式,所以引用中持有着外部类的引用。所以当串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。

 2.上例中,其实是声明了一个继承自HashMap的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化HashSet或者HashMap的子类的,从而导致串行化失败。解决办法:重新初始化为一个HashMap对象

new HashMap(map)

这种写法,推而广之,在初始化 ArrayList、Set 的时候都可以这么玩,比如你还可以这么玩:

 List<String> names = new ArrayList<String>() {
 {
 for (int i = 0; i < 10; i++) {
  add("A" + i);
 }
 }
 };
 System.out.println(names.toString()); // [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9]

二、时区问题 

背景:在操作日期时经常会出现比数据库多或少8小时的情况
原因:不同软件或系统的默认时区不一致导致的

几个时间名词: 

扫描二维码关注公众号,回复: 5324077 查看本文章
  1. GMT:格林威治标准时间 
  2. UTC:世界协调时间 
  3. DST:夏日节约时间 
  4. CST:中国标准时间 

其中GMT时间可以近似认为和UTC时间是相等的,但从精度上来说UTC时间更精确。其误差值必须保持在0.9秒以内 

CST= GMT + 8 =UTC + 8 

2.1、ES的当前时区

默认存储时间的格式是UTC时间,如果我们查询es然后获取时间日期默认的数据,会发现跟当前的时间差8个小时,这其实是正常的,因为es默认存储是用的UTC时间,所以我们需要做的就是读取long型时间戳,然后重新格式化成下面的时间戳,即可获得正确的时间 :

yyyy-MM-dd HH:mm:ss 

2.2、Mysql 当前时区

查看mysql当前时间,当前时区

show variables like "%time_zone%";

MySQL中datetime和timestamp的区别及使用

1.对于timestamp,它把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储。查询时,将其又转化为客户端当前时区进行返回;而对于datetime,不做任何改变,基本上是原样输入和输出。

2.datetime占用8个字节,timestamp占用4个字节。timestamp利用率更高。

3.二者范围不一样。timestamp范围:‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’; datetime范围:’1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。原因是,timestamp占用4字节,能表示最大的时间毫秒为2的31次方减1,也就是2147483647,换成时间刚好是2038-01-19 03:14:07.999999。

2.3、Linux当前时区

查看当前时区
命令 : "date -R"

.Java8中基本只能通过当前位置所在城市名来获取时区 

ZoneId defaultZone = ZoneId.systemDefault(); System.out.println(defaultZone); 

猜你喜欢

转载自blog.csdn.net/JiShuiSanQianLi/article/details/86496545