【对象判空+时区问题+字符串格式日期的进位+序列化和反序列化】

一、对象判空

public static boolean isEmpty(Object value) {
    
    
    if (value == null) {
    
    
        return true;
    } else if (value instanceof String) {
    
    
        return ((String)value).length() == 0;
    } else if (value instanceof Collection) {
    
    
        return ((Collection)value).size() == 0;
    } else if (value instanceof Map) {
    
    
        return ((Map)value).size() == 0;
    } else if (value instanceof String[]) {
    
    
        return ((String[])((String[])value)).length == 0;
    } else {
    
    
        return false;
    }
}

instanceof :Java 的保留关键字。作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。instanceof一般用于对象类型强制转换。instanceof是Java中的二元运算符,左边是对象,右边是类。
类的实例包含本身的实例,以及所有直接或间接子类的实例
instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误

用法:

  1. 左边的对象实例不能是基础数据类型
  2. 左边的对象实例和右边的类不在同一个继承树上
  3. null用instanceof跟任何类型比较时都是false

二、时区问题

问题:向数据库插入数据时发现有的数据插入的时间不对
最终排查出的原因为:夏令时问题
解决方法:在日期字段声明时加上时区限制,时区为上海的时区。

@JsonFormat(pattern = "yyyyMMdd", timezone = "Asia/Shanghai")

三、字符串格式日期的进位

以分钟进位:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
LocalDateTime localDateTime = LocalDateTime.parse(String.valueOf(i), dtf);
LocalDateTime plus = localDateTime.plus(i, ChronoUnit.MINUTES);
String format = dtf.format(plus);
int i = Integer.parseInt(format);

四、浅谈调用第三方jar包

第3方jar包只是个工具类,依赖不会很强的。
大胆断点,查找错误原因。
当时是调用时报空指针异常,自己也不仔细看调用。
像这种空指针异常就是有地方没有赋上值,细细看,然后赋值,就可以啦!!!

下发是当时感悟代码:

package cn.hsa.bis;

import cn.hsa.bis.api.psnDataSyncTencent.dto.PsnBasInfoQueryDTO;
import cn.hsa.hsaf.core.gateway.*;
import cn.hsa.hsaf.tencent.gateway.RioApiCaller;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

public class TencentTest {
    
    

    public static void main(String[] args) {
    
    
// 因为是一个测试类,已经不能调用配置文件和依赖注入的类了,所以需要的东西要自己new,并且参数也要自己赋值;这是需要看调用的第3方jar包看到的。
        RioApiCaller rioApiCaller = new RioApiCaller();
        rioApiCaller.setPaasid("hsa_bic");
        rioApiCaller.setToken("T6t2Q7i9rPukJhuPc6ogvXt2qNe5LWfB");
        rioApiCaller.setGatewayUrl("http://10.97.240.206:80/ebus");
        rioApiCaller.setName("rioApiCaller");
        rioApiCaller.init();  // 当时没有调用这个初始化方法,一直报空指针异常。

        PsnBasInfoQueryDTO psnBasInfoQueryDTO = new PsnBasInfoQueryDTO();
        psnBasInfoQueryDTO.setPsnMgtcode(args[0]);
        String jsonData = JSON.toJSONString(psnBasInfoQueryDTO);
        ContentBody cb = new ContentBody(jsonData);
        HttpParameters hp = HttpParameters.newBuilder()
                .api("/hsa-bic-nation-psnbasinfoservicee-queryPsnInfoByQueryDTO/")
                .version("1.0.0")
                .method("POST")
                .contentBody(cb)
                .build();
        Map<String, String> extMap = new HashMap<String, String>();
        String result = null;
        try {
    
    
            result = rioApiCaller.invoke(hp, extMap);
        } catch (ApiCallerException e) {
    
    
            e.printStackTrace();
        }
        System.out.println(result);
    }
}

五、序列化和反序列化

1、定义:
序列化:把Java对象转换为字节序列(二进制)的过程。
反序列化:把字节序列恢复为Java对象的过程。

2、作用:
序列化最重要的作用:在传递和保存对象时保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。

反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。

总结:核心作用就是对象状态的保存和重建(整个过程核心点就是字节流中所保存的对象状态及描述信息)

注:序列化是将对象状态转换为可保持或可传输的格式的过程。与序列化相对的是反序列化,反序列化将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。JSON是用于接口数据交换的格式。

json/xml的数据传递:
在数据传输(也可称为网络传输)前,先通过序列化工具类将Java对象序列化为json/xml文件。
在数据传输(也可称为网络传输)后,再将json/xml文件反序列化为对应语言的对象。

3、为什么需要序列化与反序列化
我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。

那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的!如何做到呢?这就需要Java序列化与反序列化了!

换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

总的来说可以归结为以下几点:

  1. 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;(持久化对象)
  2. 在网络上传送对象的字节序列。(网络传输对象)
  3. 通过序列化在进程间传递对象;

4.在Java中,如果一个对象要想实现序列化,必须要实现下面两个接口之一:

Serializable 接口
一个对象想要被序列化,那么它的类就要实现此接口或者它的子接口。
这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。不想序列化的字段可以使用transient修饰。
由于Serializable对象完全以它存储的二进制位为基础来构造,因此并不会调用任何构造函数,因此Serializable类无需默认构造函数,但是当Serializable类的父类没有实现Serializable接口时,反序列化过程会调用父类的默认构造函数,因此该父类必需有默认构造函数,否则会抛异常。
使用transient关键字阻止序列化虽然简单方便,但被它修饰的属性被完全隔离在序列化机制之外,导致了在反序列化时无法获取该属性的值,而通过在需要序列化的对象的Java类里加入writeObject()方法与readObject()方法可以控制如何序列化各属性,甚至完全不序列化某些属性或者加密序列化某些属性。

Externalizable 接口
它是Serializable接口的子类,用户要实现的writeExternal()和readExternal() 方法,用来决定如何序列化和反序列化。
因为序列化和反序列化方法需要自己实现,因此可以指定序列化哪些属性,而transient在这里无效。
对Externalizable对象反序列化时,会先调用类的无参构造方法,这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出java.io.InvalidException: no valid constructor异常,因此Externalizable对象必须有默认构造函数,而且必需是public的。
使用:
你只想隐藏一个属性,比如用户对象user的密码pwd,如果使用Externalizable,并除了pwd之外的每个属性都写在writeExternal()方法里,这样显得麻烦,可以使用Serializable接口,并在要隐藏的属性pwd前面加上transient就可以实现了。如果要定义很多的特殊处理,就可以使用Externalizable。
Serializable 中的writeObject()方法与readObject()方法科可以实现自定义序列化,而Externalizable 中的writeExternal()和readExternal() 方法也可以,他们有什么异同呢?
readExternal(),writeExternal()两个方法,这两个方法除了方法签名和readObject(),writeObject()两个方法的方法签名不同之外,其方法体完全一样。
需要指出的是,当使用Externalizable机制反序列化该对象时,程序会使用public的无参构造器创建实例,然后才执行readExternal()方法进行反序列化,因此实现Externalizable的序列化类必须提供public的无参构造。
虽然实现Externalizable接口能带来一定的性能提升,但由于实现ExternaLizable接口导致了编程复杂度的增加,所以大部分时候都是采用实现Serializable接口方式来实现序列化。

5.序列化版本----serialVersionUID字段
在序列化过程中,可以控制序列化的版本。该字段为被序列化对象中的serialVersionUID字段。

一个对象数据,在反序列化过程中,如果序列化串中的serialVersionUID与当前对象值不同,则反序列化失败,否则成功。
如果serialVersionUID没有显式生成,系统就会自动生成一个。生成的输入有:类名、类及其属性修饰符、接口及接口顺序、属性、静态初始化、构造器。任何一项的改变都会导致serialVersionUID变化。
属性的变化都会导致自动生成的serialVersionUID发生变化。例如,对于对象A,我们生成序列化的S(A),然后修改A的属性,则此时A的serialVersionUID发生变化。反序列化时,S(A)与A的serialVersionUID不同,无法反序列化。会报序列号版本不一致的错误。
为了避免这种问题, 一般系统都会要求实现serialiable接口的类显式的生明一个serialVersionUID。显式定义
serialVersionUID的两种用途:
希望类的不同版本对序列化兼容时,需要确保类的不同版本具有相同的serialVersionUID;
不希望类的不同版本对序列化兼容时,需要确保类的不同版本具有不同的serialVersionUID。
如果我们保持了serialVersionUID的一致,则在反序列化时,对于新增的字段会填入默认值null(int的默认值0),对于减少的字段则直接忽略。

猜你喜欢

转载自blog.csdn.net/m0_46459413/article/details/128802417