亲宝软件园·资讯

展开

Java enum 传输 浅谈Java中是否直接可以使用enum进行传输

Jeff、yuan 人气:4

背景

我们在进行传输的时候 会有一些状态值,如Status为1代表删除,为0代表失败或者怎么样的。只传输一个)0或者1过去给第三方(此处不包括给前端),如果没有契约第三方会不认识你这个是什么意思,那我们在平时写业务逻辑的时候使用枚举很轻易就知道了什么状态什么值。所以我们在构建DTO对象的时候里面放一个枚举来表示。

首先在阿里的规范里是这样说的:

【强制】二方库里可以定义枚举类型,参数可以使用枚举类型,但是接口返回值不允许使用枚举类型或者包含枚举类型的 POJO 对象。
那到底为啥不能用呢?

枚举

首先我们得先思考一下枚举是否可以进行序列化,我们在把对象进行传输的时候需要将这个对象序列化为字节序列进行传输(在linux中一切皆文件,JVM虚拟机将对象变为字节给到内核通过传输协议进行打包传)枚举在进行编译后会生成一个相关的类,这个类,这个类继承了JavaAPI中的java.lang.Enum类。那么我们看看这个类,毫无疑问可以序列化。继承了Serializable接口。那么就肯定就是可以序列化了。

Enum实战序列化

1. 创建一个枚举类

package SerializableEnum;

/**
 * @Author:yuanxindong
 * @Date:2020/5/101:33
 */
public enum PersonEnum {
 /**
  * 小圆
  */
 YUANXINDONG("yuanxindong",1);

 ;
 private String age;
 private int i;

 PersonEnum(String yuanxindong, int i) {
  this.age = yuanxindong;
  this.i = i;
 }}

2.将枚举类放入Person对象,通过本地序列化存入target文件夹中,再进行反序列化,读取查看枚举的值

package SerializableEnum;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @Author:yuanxindong
 * @Date:2020/5/101:31
 */
public class Person implements Serializable {
 private String name;
 PersonEnum a;

 public void setName(String name) {
  this.name = name;
 }

 public void setA(PersonEnum a) {
  this.a = a;
 }

 public String getName() {
  return name;
 }

 public PersonEnum getA() {
  return a;
 }

 @Override
 public String toString() {
  return "Person{" +
    "name='" + name + '\'' +
    ", a=" + a +
    '}';
 }

 public static void main(String[] args) throws IOException, ClassNotFoundException {
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
  Person p = new Person();
  p.setA(PersonEnum.YUANXINDONG);
  p.setName("小圆");
  oos.writeObject(p);

  ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\workCode\\票税助手\\aresV3\\springCodestudy\\object.txt"));
  Person brady = (Person) ois.readObject();
  brady.getA();

  System.out.println(brady);
 }
}

执行结果:


但是在控制台输出的对象是枚举的命名,没有枚举中的值,这时为什么呢?


==
我用的是aliFastJson转还为JsonObject的我们看看他里面的实现。只是拿了对应枚举的name(感觉是个坑啊),这也阿里规范中不能使用枚举放在DTO的原因之一吧==


上面的内容整明了枚举是可以进行序列化的,是可以被传输的,他的实现也是通过类来实现的,除了fastJSON那一步,使用都没有问题的。其他角度考虑

借鉴知乎

使用枚举的确会带来扩展兼容性的问题,这点很多答主都说的很好了,我就说一下为什么参数上可以使用枚举的原因吧。咱们先假定对枚举的扩展只是新增值,而不是减少值。比如说性别中本来是男和女,现在要增加一个transgender, 但我们极少极少会有需求说,把性别中的已有男或者女去掉。(我觉得这个假设是参数可以使用枚举型的前提)在这个假定下如果我们在接口中使用枚举型,如孤尽兄在java开发手册中所述,分为参数和返回值两种情况。不管是微服务之间的互相调用,还是手机客户端到服务器的调用,在不停机的情况下,服务器端和客户端是很难一起更新的,往往我们是服务器端先来支持新feature,然后再来逐步更新客户端。我想孤尽兄说参数可以使用枚举型,也是基于这种更新升级方式。因为服务器端如果突然开始返回transgender这个新性别,客户端吃不进去(反序列化不了),客户端就炸了。但如果服务器端只是在参数上开始接受新性别,那就不怕老客户端,反正老客户端还在那里继续发送男和女这两种性别,服务器端都认识,就不会出错。两边可以一直相安无事,慢慢等所有客户端都升级。但是呢,如果我们用string来代替枚举,服务器端贸然返回一个新的值,客户端不知道怎么处理,也可能会产生其他问题,比如说钱算错了之类业务层面的问题。所以客户端代码可能要先更新一点,让其能处理这个新的值。我觉得阿里把这个标准放在手册里,也是多年的经验教训,两害相权取其轻吧。因为很多应用是没法强制客户端一起更新的。尤其是手机移动客户端,ios可能还要审核,很难做到客户端和服务器端同步更新。如果是微服务,也很难在不停机的情况下,把通过枚举耦合两个微服务一起更新。

看完大佬的说法个人感觉:

是的你在一个项目中维护是没有什么问题。但是多个项目使用同一个枚举怎么搞。要么这个枚举一处动即全动。所有的项目使用这一个枚举。比如说全公司有一个通用的发票类型枚举,有几个状态值代表一钟发票类型,于是这个枚举维护到公共配置上,通过动态加载技术,在每次发布或者有修改的时候进行动态加载。感觉同完美。小白的YY。落地难吗??试一试。后面更新。

加载全部内容

相关教程
猜你喜欢
用户评论