继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

《手册》详解 第3节 Java序列化引发的血案课后题参考答案

明明如月
关注TA
已关注
手记 59
粉丝 3858
获赞 1465

一、背景

《阿里巴巴 Java开发手册》详解专栏  的第 3节,主要讲解了序列化的概念,序列化的主要实现方式,以及序列化和反序列化的一些坑点。

并给出了一个课后题:

给出一个PersonTransit类,一个Address类,假设Address是其他 jar 包中的类,没实现序列化接口。请使用今天讲述的自定义的函数writeObjectreadObject函数实现PersonTransit对象的序列化,要求反序列化后address的值正常。

@Data
public class PersonTransit implements Serializable {    
  private Long id;
  private String name;
  private Boolean male;
  private List<PersonTransit> friends;
  private transient Address address;
}

@Data
@AllArgsConstructor
public class Address {    
  private String detail;  
}

序列化主要有两个困难:

1 transient 关键字,序列化时默认不序列化该字段。(新加的,增加难度)

2 假设 Address 是第三方 jar 包中的类,不允许修改实现序列化接口。

二、分析

我们通过专栏的介绍还有序列化接口java.io.Serializable的注释可知,可以自定义序列化方法和反序列化方法:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

实现序列化和反序列化不可序列化的属性,也可以对序列化的数据进行数据的加密和解密处理。


三、参考代码

@Data
public class PersonTransit implements Serializable {

    private Long id;

    private String name;

    private Boolean male;

    private List<PersonTransit> friends;

    private transient Address address;

    /**
     * 自定义序列化写方法
     */
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(address.getDetail());
    }

    /**
     * 自定义反序列化读方法
     */
    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        this.setAddress(new Address( (String) ois.readObject()));
    }
}


单元测试

@Test
public void testJDKSerialOverwrite() throws IOException, ClassNotFoundException {
    PersonTransit person = new PersonTransit();
    person.setId(1L);
    person.setName("张三");
    person.setMale(true);
    person.setFriends(new ArrayList<>());

    Address address = new Address();
    address.setDetail("某某小区xxx栋yy号");
    person.setAddress(address);

    // 序列化
    JdkSerialUtil.writeObject(file, person);
    // 反序列化
    PersonTransit personTransit = JdkSerialUtil.readObject(file);
    // 判断是否相等
    Assert.assertEquals(personTransit.getName(), person.getName());
    Assert.assertEquals(personTransit.getAddress().getDetail(), person.getAddress().getDetail());
}

用到的工具类:

public class JdkSerialUtil {

    public static <T> void writeObject(File file, T data) throws IOException {
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));) {
            objectOutputStream.writeObject(data);
            objectOutputStream.flush();
        }
    }

    public static <T> void writeObject(ByteArrayOutputStream outputStream, T data) throws IOException {
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);) {
            objectOutputStream.writeObject(data);
            objectOutputStream.flush();
        }
    }

    public static <T> T readObject(File file) throws IOException, ClassNotFoundException {
        FileInputStream fin = new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(fin);
        return (T) objectInputStream.readObject();
    }

    public static <T> T readObject(ByteArrayInputStream inputStream) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        return (T) objectInputStream.readObject();
    }
}


通过单元测试验证了我们编写代码的正确性。


四、总结

大家学习知识时要敢于尝试,写不出来说明理解不够到位,找一些例子去参考,只有自己能自主改编才能说明真正会运用。

只有基础扎实,学的更多,才更容易找到问题的解决方法。

学习时要多看源码和源码的注释,这样可以学到更多。


想了解更多《手册》详解的更多内容,想学习更多开发和避坑技巧,少走弯路,请关注《阿里巴巴Java 开发手册》详解专栏

大家购买前有啥疑问或者想和其他读者交流可以用base64算法解密以下内容: 5re75Yqg5b6u5L+hICBmZW5neWVsaWFvemhhaSAg5bm255WZ6KiA77ya5Yqg5YWl44CK5omL5YaM44CL6K+m6Kej5LiT5qCP6K+76ICF5Lqk5rWB576k44CC




打开App,阅读手记
9人推荐
发表评论
随时随地看视频慕课网APP

热门评论

不错, 学习了

查看全部评论