[关闭]
@nextleaf 2018-08-23T12:15:37.000000Z 字数 19207 阅读 966

2018-08-22 工作日志

Java 序列化 多线程


1. 序列化

一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
两种用途:

1.1 serialVersionUID的作用

serialVersionUID适用于Java的序列化机制。
简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。
序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则会出InvalidCastException异常。

1.2 序列化示例:

  1. package com.nl.sx820.io.stream.serializable;
  2. import com.alibaba.fastjson.JSON;
  3. import com.nl.statictest.UserTest;
  4. import java.io.*;
  5. import java.util.Date;
  6. /**
  7. * Created with IntelliJ IDEA 2018.
  8. * Description:Serializable序列化
  9. * 使用ObjectInputStream和阿里巴巴fastjson序列化以及反序列化
  10. *
  11. * @author: 黄昭鸿
  12. * @date: 2018-08-21
  13. * Time: 16:00
  14. *
  15. * 使用阿里 fastjson 作为JSON MessageConverter
  16. * https://github.com/alibaba/fastjson/wiki/JSONField
  17. *
  18. * @JSONField(serialize=false)指定字段不序列化(java默认的不序列化方法是在属性上加关键字“transient”,反序列化时该属性为默认值)
  19. * @JSONField(ordinal = 1)使用ordinal指定字段的顺序,default 0,从一开始
  20. * @JSONField(format="yyyy-MM-dd",ordinal = 4)
  21. */
  22. public class SerializableDemo {
  23. public static void main(String[] args) {
  24. UserTest userTest = new UserTest("黄", "123456", 12, 16.6, new Date());
  25. //新建两个文件
  26. File file = new File("E:" + File.separator + "Downloads" + File.separator + userTest.getClass().getName() + ".dat");
  27. File fastjsonfile = new File("E:" + File.separator + "Downloads" + File.separator + "fastjson.dat");
  28. //把对象序列化保存到文件中
  29. objToFileUseObjectOutputStream(file, userTest);
  30. //使用阿里巴巴fastjson序列化,String text = JSON.toJSONString( Object object);
  31. objToFileUseFastjson(fastjsonfile, userTest);
  32. //反序列化,使用ObjectInputStream
  33. System.out.println("使用ObjectInputStream反序列化:");
  34. UserTest userTest1 = (UserTest) readFileUseObjectInputStream(file);
  35. System.out.println(userTest1);
  36. //反序列化,使用阿里巴巴fastjson
  37. System.out.println("使用阿里巴巴fastjson反序列化:");
  38. UserTest userTest2 = JSON.parseObject(readFileUseFileReader(fastjsonfile), UserTest.class);
  39. System.out.println(userTest2);
  40. }
  41. //序列化对象到文件,使用ObjectOutputStream
  42. public static void objToFileUseObjectOutputStream(File targetfile, Object object) {
  43. try {
  44. //处理流套着节点流,节点流里套着文件
  45. ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(targetfile));
  46. objectOutputStream.writeObject(object);
  47. objectOutputStream.flush();
  48. objectOutputStream.close();
  49. } catch (FileNotFoundException e) {
  50. e.printStackTrace();
  51. } catch (IOException e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. //序列化对象到文件,使用fastjson
  56. public static void objToFileUseFastjson(File targetfile, Object object) {
  57. try {
  58. BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(targetfile));
  59. bufferedWriter.write(JSON.toJSONString(object));
  60. bufferedWriter.flush();
  61. bufferedWriter.close();
  62. } catch (FileNotFoundException e) {
  63. e.printStackTrace();
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. }
  67. }
  68. //反序列化,使用ObjectInputStream
  69. public static Object readFileUseObjectInputStream(File file) {
  70. try {
  71. //处理流套着节点流,节点流里套着文件
  72. ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
  73. //读取文件并反序列化
  74. UserTest temp = (UserTest) objectInputStream.readObject();
  75. //System.out.println(temp);
  76. objectInputStream.close();
  77. return temp;
  78. } catch (FileNotFoundException e) {
  79. e.printStackTrace();
  80. } catch (IOException e) {
  81. e.printStackTrace();
  82. } catch (ClassNotFoundException e) {
  83. e.printStackTrace();
  84. }
  85. return null;
  86. }
  87. //读取文件内容到String
  88. public static String readFileUseFileReader(File file) {
  89. FileReader fileReader = null;
  90. String string = "";
  91. try {
  92. fileReader = new FileReader(file);
  93. char[] chars = new char[(int) file.length()];
  94. /* for (int i = 0; i <fileReader.read(chars); i++) {
  95. string.concat(String.valueOf(chars[i]));
  96. }*/
  97. fileReader.read(chars);
  98. string=new String(chars);
  99. } catch (FileNotFoundException e) {
  100. e.printStackTrace();
  101. } catch (IOException e) {
  102. e.printStackTrace();
  103. } finally {
  104. if (fileReader != null) {
  105. try {
  106. fileReader.close();
  107. } catch (IOException e) {
  108. e.printStackTrace();
  109. }
  110. }
  111. }
  112. System.out.println("读取:"+string);
  113. return string;
  114. }
  115. }

1.3 序列化机制

使用Java默认序列化机制时,实体类必须实现Serializable接口,实现后如果该类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的,完全相同的一个类,在不同的编译器上编译,自动生成的serialVersionUID有可能会不一致,导致无法完成反序列化,所以通常会显式地定义serialVersionUID。


如上图,假设是两台计算机上(相同)的实体类,显示地定义了相同的serialVersionUID;
序列化得到
删除某字段(属性,假设为),再通过反序列化时,得到的对象将没有字段(属性);
transient某字段(属性,假设为),再通过反序列化时,得到的对象里字段(属性)的值为初始化值(引用类型为null,基本类型为相应的初始默认值);
添加新字段(属性,假设为),再通过反序列化时,得到的对象会有字段(属性),其值为初始化值。

实例见附录

另外,序列化保存的是对象的状态,类的状态(比如静态变量)不会保存。
父类的序列化参见父类的序列化
总结:反序列化时,总是以的"结构"为准

实体类UserTest.java

  1. /**
  2. * 使用阿里 fastjson 作为JSON MessageConverter
  3. *https://github.com/alibaba/fastjson/wiki/JSONField
  4. *
  5. * @JSONField(serialize=false)指定字段不序列化(java默认的不序列化方法是在属性上加关键字“transient”,反序列化时该属性为默认值)
  6. * @JSONField(ordinal = 1)使用ordinal指定字段的顺序,default 0,从一开始
  7. * @JSONField(format="yyyy-MM-dd",ordinal = 4)
  8. *
  9. * String text = JSON.toJSONString(obj); //序列化
  10. * VO vo = JSON.parseObject("{...}", VO.class); //反序列化
  11. * 泛型反序列化:
  12. * import com.alibaba.fastjson.TypeReference;
  13. * List<VO> list = JSON.parseObject("...", new TypeReference<List<VO>>() {});
  14. *
  15. * 如果需要输出对象属性中的null为空值,怎么做
  16. * JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue);
  17. *
  18. * String text = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
  19. * */
  20. public class UserTest implements Serializable {
  21. private static final long serialVersionUID = 9166711291168034786L;
  22. //static final long serialVersionUID=1L;
  23. @JSONField(ordinal = 1)
  24. private String username;
  25. @JSONField(ordinal = 2)
  26. private String password;
  27. @JSONField(ordinal = 3)
  28. private int experience;
  29. @JSONField(ordinal = 4)
  30. private double money;
  31. @JSONField(ordinal = 5,format="yyyy年MM月dd日")
  32. private Date regtime;
  33. public UserTest() {}
  34. public UserTest(String username, String password, int experience, double money, Date regtime) {
  35. this.username = username;
  36. this.password = password;
  37. this.experience = experience;
  38. this.money = money;
  39. this.regtime = regtime;
  40. }
  41. @Override
  42. public String toString() {
  43. return this.username+","+this.password+"(密码),经验:"+this.experience+",钱:"+this.money+",注册时间:"+this.regtime;
  44. }
  45. //省略setter和getter方法,项目中记得要补上
  46. }

2. 多线程

一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
隐含的主线程:main()

2.1 一个线程的生命周期

线程的生命周期

2.2 单线程

  1. package com.nl.sx822.multithread;
  2. public class SingleThread {
  3. public static void aVoid(String str) {
  4. System.out.println("a:" + str);
  5. }
  6. public static void bVoid(String str) {
  7. System.out.println("b:");
  8. aVoid(str);
  9. }
  10. public static void main(String[] args) {
  11. System.out.println("main:");
  12. System.out.println("单线程:b-->a");
  13. bVoid("黄");
  14. }
  15. }

2.3 多线程

2.3.1 方式一,继承Thread类,子线程和主线程并发:

  1. package com.nl.sx822.multithread;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:多线程——继承Thread方式
  5. * 主线程:输出1-20
  6. * 子线程:输出1-20
  7. * 实现步骤:【1】-【5】
  8. * .yield()调用此方法的线程释放当前CPU执行权,但有可能被再次选中执行
  9. * .join()在A线程(此例中为main)中调用B线程的join()方法,表示:当执行到此方法时,A线程等待B执行完毕,A线程再接着执行join()后的代码。
  10. * .isAlive() 线程是否活着,通常用来判断线程是否已完成
  11. * .sleep()
  12. * .getPriority()获取线程优先级
  13. * .setPriority()设置优先级,MAX_PRIORITY(10),NORM_PRIORITY(5),MIN_PRIORITY(1)
  14. *
  15. * @author: 黄昭鸿
  16. * @date: 2018-08-22
  17. * Time: 10:40
  18. */
  19. /**
  20. * 类说明:【1】继承于Thread的子类
  21. * 【2】重写run()方法,作为子线程
  22. */
  23. class Sub extends Thread {
  24. @Override
  25. public void run() {
  26. //Thread.currentThread(),当前线程引用
  27. try {
  28. for (int i = 1; i < 21; i++) {
  29. String s = Thread.currentThread().getName() + ":" + i;
  30. System.out.println(s);
  31. sleep(300);
  32. }
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38. public class Multithread {
  39. public static void main(String[] args) {
  40. System.out.println("出现交替打印是明显的多线程体现");
  41. //【3】创建子线程类的对象
  42. Sub s = new Sub();
  43. Sub s2 = new Sub();
  44. //【4】调用start方法来启动线程
  45. s.setName("1号子线程");
  46. s.start();
  47. s2.setName("2号子线程");
  48. s2.start();
  49. //s.run()//直接调用run()方法会变成单线程
  50. //【5】主线程
  51. for (int j = 1; j < 21; j++) {
  52. String s1 = Thread.currentThread().getName() + ":" + j;
  53. if (j == 15) {
  54. try {
  55. s2.join();
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. //线程是否活着,用来判断线程是否已完成
  61. System.out.println(s2.isAlive());
  62. System.out.println(s1);
  63. }
  64. }
  65. }

2.3.2 方式二,实现Runnable类,(只有子线程并发?):

  1. package com.nl.sx822.multithread;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:多线程——实现Runnable类的方式
  5. * 步骤:【1】-【5】
  6. *
  7. * @author: 黄昭鸿
  8. * @date: 2018-08-22
  9. * Time: 15:50
  10. */
  11. /**
  12. * 类说明:【1】实现Runnable类,实现类记为A
  13. * 【2】重写run()方法
  14. */
  15. class SubThread implements Runnable {
  16. /**
  17. * When an object implementing interface <code>Runnable</code> is used
  18. * to create a thread, starting the thread causes the object's
  19. * <code>run</code> method to be called in that separately executing
  20. * thread.
  21. * <p>
  22. * The general contract of the method <code>run</code> is that it may
  23. * take any action whatsoever.
  24. *
  25. * @see Thread#run()
  26. */
  27. @Override
  28. public void run() {
  29. for (int i = 0; i < 100; i++) {
  30. //if (i%2==0){
  31. System.out.println(Thread.currentThread().getName() + i);
  32. //}
  33. }
  34. }
  35. }
  36. public class Multithread2 {
  37. public static void main(String[] args) {
  38. //【3】创建A类的对象该对象记为a
  39. SubThread subThread = new SubThread();
  40. System.out.println("创建子线程类的对象");
  41. //【4】利用对象a创建子线程类的对象
  42. Thread thread1 = new Thread(subThread);
  43. Thread thread2 = new Thread(subThread);
  44. Thread thread3 = new Thread(subThread);
  45. thread1.setName("1号子线程");
  46. thread2.setName("2号子线程");
  47. thread3.setName("3号子线程");
  48. //【5】调用start方法来启动线程
  49. thread1.start();
  50. thread2.start();
  51. thread3.start();
  52. //main线程先执行,只有子线程并发?
  53. for (int i = 0; i < 100; i++) {
  54. System.out.println(Thread.currentThread().getName());
  55. }
  56. }
  57. }

2.3.3 多线程应用例子——模拟多窗口卖票:

其一

  1. package com.nl.sx822.multithread.demo;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:多线程(继承Thread类方式)——模拟多窗口卖票
  5. *
  6. * @author: 黄昭鸿
  7. * @date: 2018-08-22
  8. * Time: 15:37
  9. */
  10. class Window extends Thread {
  11. //总票数,static
  12. static int ticket = 100;
  13. @Override
  14. public void run() {
  15. while (true) {
  16. if (ticket > 0) {
  17. System.out.println(Thread.currentThread().getName() + ":" + ticket--);
  18. } else {
  19. break;
  20. }
  21. }
  22. }
  23. }
  24. public class StationTicketWindow {
  25. public static void main(String[] args) {
  26. System.out.println();
  27. Window window1 = new Window();
  28. Window window2 = new Window();
  29. Window window3 = new Window();
  30. window1.setName("1号窗口");
  31. window2.setName("2号窗口");
  32. window3.setName("3号窗口");
  33. window1.start();
  34. window2.start();
  35. window3.start();
  36. }
  37. }

其二

  1. package com.nl.sx822.multithread.demo;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:多线程(实现Runnable类方式)——模拟多窗口卖票
  5. *
  6. * @author: 黄昭鸿
  7. * @date: 2018-08-22
  8. * Time: 16:24
  9. */
  10. class Window2 implements Runnable {
  11. int ticket = 100;
  12. @Override
  13. public void run() {
  14. while (true) {
  15. if (ticket > 0) {
  16. /* try 处代码将引发线程同步问题
  17. try {
  18. Thread.sleep(10);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }*/
  22. System.out.println(Thread.currentThread().getName()+":"+ticket--);
  23. } else {
  24. break;
  25. }
  26. }
  27. }
  28. }
  29. public class StationTicketWindow2 {
  30. public static void main(String[] args) {
  31. Window2 subThread = new Window2();
  32. System.out.println("创建子线程对象");
  33. Thread thread1 = new Thread(subThread);
  34. Thread thread2 = new Thread(subThread);
  35. Thread thread3 = new Thread(subThread);
  36. thread1.setName("1号窗口");
  37. thread2.setName("2号窗口");
  38. thread3.setName("3号窗口");
  39. thread1.start();
  40. thread2.start();
  41. thread3.start();
  42. //main线程不参与子线程的并发??????
  43. for (int i = 0; i < 100; i++) {
  44. System.out.println(Thread.currentThread().getName());
  45. }
  46. }
  47. }

2.4 线程同步

针对上述“多线程(实现Runnable类方式)——模拟多窗口卖票”程序中try代码块可能引发的多线程并发时的安全问题,可使用Java线程同步机制来解决此线程安全问题。

  1. class A {}
  2. class Window2 implements Runnable {
  3. int ticket = 100;
  4. //同步监视器(共用的一把锁a)
  5. A obj = new A();
  6. @Override
  7. public void run() {
  8. while (true) {
  9. //使用Java线程同步机制实现线程安全
  10. // 同步锁,括号里不能new新对象,否则不同步,此处用this也可以,this代表Window2的对象,在main方法中只被new了1次
  11. synchronized (obj) {
  12. if (ticket > 0) {
  13. /* try 处代码将引发多线程并发时的安全问题(线程同步问题),一个线程操作共享变量ticket且未完成时,另一个线程也对ticket进行操作。
  14. * 解决:必须让一个线程操作共享数据完毕后,其他线程才有机会参与共享数据的操作
  15. * */
  16. try {
  17. Thread.sleep(100);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. System.out.println(Thread.currentThread().getName() + ":" + ticket--);
  22. } else {break;}
  23. }
  24. }
  25. }
  26. }

synchronized置于方法声明中

  1. class Window3 implements Runnable {
  2. int ticket = 100;
  3. //synchronized修饰方法时,其同步监视器(锁)为this。
  4. @Override
  5. public void run() {
  6. while (true) {
  7. if (show()){break;}
  8. }
  9. }
  10. public synchronized boolean show(){
  11. if (ticket > 0) {
  12. try {
  13. Thread.sleep(10);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. System.out.println(Thread.currentThread().getName() + ":" + ticket--);
  18. return false;
  19. }else {return true;}
  20. }
  21. }

2.5 线程间通信

java.lang.Object的三个方法:
只在synchronized代码块或方法中使用。
wait();令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,二当前线程排队等候在此对资源的访问。
notify();唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
notifyAll();唤醒正在排队等待资源的所有线程结束等待。

  1. package com.nl.sx822.multithread.demo;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:俩线程交替打印1-100
  5. *
  6. * @author: 黄昭鸿
  7. * @date: 2018-08-23
  8. * Time: 11:36
  9. */
  10. class SubThread1 implements Runnable {
  11. private int anInt = 1;
  12. @Override
  13. public void run() {
  14. while (true) {
  15. synchronized (this) {
  16. notify();
  17. if (anInt <= 100) {
  18. try {
  19. Thread.sleep(100);
  20. } catch (InterruptedException e) {e.printStackTrace();}
  21. System.out.println(Thread.currentThread().getName() + ":" + anInt++);
  22. } else {break;}
  23. try {
  24. wait();
  25. } catch (InterruptedException e) {e.printStackTrace();}
  26. }
  27. }
  28. }
  29. }
  30. public class Multithread4 {
  31. public static void main(String[] args) {
  32. SubThread1 subThread1 = new SubThread1();
  33. Thread thread1 = new Thread(subThread1);
  34. thread1.setName("甲");
  35. Thread thread2 = new Thread(subThread1);
  36. thread2.setName("乙");
  37. //Thread thread3 = new Thread(subThread1);
  38. //thread3.setName("3号");
  39. //thread3.start();
  40. thread1.start();
  41. thread2.start();
  42. }
  43. }

2.6 线程死锁

2.7 线程控制:挂起、停止和恢复

2.8 守护线程和用户线程

守护线程是用来服务用户线程的,通过在start方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
Java垃圾回收就是一个典型的守护线程。
若JVM中都是守护线程,当前JVM将推出。


疑问:

  1. public class Multithread2 {
  2. public static void main(String[] args) {
  3. SubThread subThread = new SubThread();
  4. System.out.println("创建子线程对象");
  5. Thread thread1 = new Thread(subThread);
  6. Thread thread2 = new Thread(subThread);
  7. Thread thread3 = new Thread(subThread);
  8. thread1.setName("1号子线程");
  9. thread2.setName("2号子线程");
  10. thread3.setName("3号子线程");
  11. thread1.start();
  12. thread2.start();
  13. thread3.start();
  14. //main线程不参与子线程的并发??????
  15. for (int i = 0; i < 100; i++) {
  16. System.out.println(Thread.currentThread().getName());
  17. }
  18. }
  19. }

附录:

transient字段、增加字段、减少字段对序列化的影响

其一

  1. package com.nl.sx822.serializable;
  2. /**
  3. * Created with IntelliJ IDEA 2018.
  4. * Description:使用Java默认序列化机制进行序列化
  5. * transient字段(属性)、增加字段(属性)、减少字段(属性)对默认机制序列化的影响
  6. *
  7. * 另见package com.nl.sx820.io.stream.serializable;
  8. *
  9. * @author: 黄昭鸿
  10. * @date: 2018-08-22
  11. * Time: 23:00
  12. */
  13. import cn.hutool.core.lang.Console;
  14. import java.io.*;
  15. import java.util.Date;
  16. public class SerializableDemo2 {
  17. public static void main(String[] args) {
  18. //UserA userA=new UserA("A", "123456", 10, 166, new Date());
  19. //UserB userB=new UserB("B", "654123", 20, 199, new Date());
  20. UserA userA=new UserA();
  21. UserB userB=new UserB();
  22. File fileA = new File("E:" + File.separator + "Downloads" + File.separator + userA.getClass().getName() + ".data");
  23. File fileB = new File("E:" + File.separator + "Downloads" + File.separator + userB.getClass().getName() + ".data");
  24. //序列化
  25. //objToFileUseObjectOutputStream(fileA,userA);
  26. //objToFileUseObjectOutputStream(fileB,userB);
  27. System.out.println("反序列化");
  28. //如果类比序列化文件多了一个sex新字段,反序列化后对象的对应字段值为初始化值
  29. //如果类比序列化文件少了一个password字段,反序列化后对象将没有password字段
  30. UserA a= (UserA) readFileUseObjectInputStream(fileA);
  31. //UserA cannot be cast to UserB//即使UID一致也报错
  32. //UserB b= (UserB) readFileUseObjectInputStream(fileA);
  33. //如果类transient某个字段,反序列化后对象的对应字段值为初始化值
  34. UserB b= (UserB) readFileUseObjectInputStream(fileB);
  35. System.out.println(a);
  36. System.out.println(b);
  37. }
  38. //序列化对象到文件,使用对象字节流ObjectOutputStream
  39. public static void objToFileUseObjectOutputStream(File targetfile, Object object) {
  40. try {
  41. //处理流套着节点流,节点流里套着文件
  42. ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(targetfile));
  43. objectOutputStream.writeObject(object);
  44. objectOutputStream.flush();
  45. objectOutputStream.close();
  46. } catch (FileNotFoundException e) {
  47. e.printStackTrace();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. //反序列化,使用ObjectInputStream
  53. public static Object readFileUseObjectInputStream(File file) {
  54. try {
  55. //处理流套着节点流,节点流里套着文件
  56. ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
  57. //读取文件并反序列化
  58. Object temp = objectInputStream.readObject();
  59. //System.out.println(temp);
  60. objectInputStream.close();
  61. return temp;
  62. } catch (FileNotFoundException e) {
  63. e.printStackTrace();
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. } catch (ClassNotFoundException e) {
  67. e.printStackTrace();
  68. }
  69. return null;
  70. }
  71. }
  72. class UserA implements Serializable {
  73. private static final long serialVersionUID = 3187377513146605030L;
  74. private String username;
  75. private String password;
  76. private String sex;
  77. private int experience;
  78. private double money;
  79. private Date regtime;
  80. public UserA() {}
  81. @Override
  82. public String toString() {
  83. return this.username+","+this.password+",性别:"+this.sex+",经验:"+this.experience+",钱:"+this.money+",注册时间:"+this.regtime;
  84. }
  85. //省略setter和getter方法,项目中记得要补上
  86. }
  87. class UserB implements Serializable{
  88. private static final long serialVersionUID = 9166711291168034788L;
  89. private String username;
  90. private transient String password;
  91. private int experience;
  92. private double money;
  93. private Date regtime;
  94. public UserB() {}
  95. @Override
  96. public String toString() {
  97. return this.username+","+this.password+",经验:"+this.experience+",钱:"+this.money+",注册时间:"+this.regtime;
  98. }
  99. //省略setter和getter方法,项目中记得要补上
  100. }

其二

  1. package com.nl.sx822.serializable;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.annotation.JSONField;
  4. import java.io.*;
  5. import java.time.LocalDate;
  6. /**
  7. * Created with IntelliJ IDEA 2018.
  8. * Description:使用阿里巴巴fastjson序列化和反序列化
  9. * 增加字段、减少字段(属性)对阿里序列化的影响
  10. * JSONField(serialize=false)指定字段不序列化
  11. * @author: 黄昭鸿
  12. * @date: 2018-08-23
  13. * Time: 19:21
  14. */
  15. public class SerializableAliDemo {
  16. public static void main(String[] args) {
  17. UserC userC = new UserC("张铁牛","甲","男",LocalDate.now());
  18. //D比C少一个字段
  19. UserD userD = new UserD("张铁男","乙","女");
  20. File fileC = new File("E:" + File.separator + "Downloads" + File.separator + userC.getClass().getName() + ".data");
  21. File fileD = new File("E:" + File.separator + "Downloads" + File.separator + userD.getClass().getName() + ".data");
  22. //使用阿里巴巴fastjson序列化,String text = JSON.toJSONString( Object object);
  23. objToFileUseFastjson(fileC, userC);
  24. objToFileUseFastjson(fileD, userD);
  25. //反序列化,不要求两个类必须一致
  26. UserC c = JSON.parseObject(readFileUseFileReader(fileC),UserC.class);
  27. //UserD转UserC
  28. UserC c2 = JSON.parseObject(readFileUseFileReader(fileD),UserC.class);
  29. //UserC转UserD
  30. UserD d = JSON.parseObject(readFileUseFileReader(fileC),UserD.class);
  31. System.out.println();
  32. //正常反序列化
  33. System.out.println(c);
  34. //类字段增加,反序列化后对象“新”字段的值为初始化值。
  35. System.out.println(c2);
  36. //类字段减少,反序列化时将忽略序列化文件中多出的字段。
  37. System.out.println(d);
  38. }
  39. //序列化对象到文件,使用fastjson
  40. public static void objToFileUseFastjson(File targetfile, Object object) {
  41. try {
  42. BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(targetfile));
  43. bufferedWriter.write(JSON.toJSONString(object));
  44. bufferedWriter.flush();
  45. bufferedWriter.close();
  46. } catch (FileNotFoundException e) {
  47. e.printStackTrace();
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. //读取文件内容到String
  53. public static String readFileUseFileReader(File file) {
  54. FileReader fileReader = null;
  55. String string = "";
  56. try {
  57. fileReader = new FileReader(file);
  58. char[] chars = new char[(int) file.length()];
  59. /* for (int i = 0; i <fileReader.read(chars); i++) {
  60. string.concat(String.valueOf(chars[i]));
  61. }*/
  62. fileReader.read(chars);
  63. string = new String(chars);
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. } finally {
  67. if (fileReader != null) {
  68. try {
  69. fileReader.close();
  70. } catch (IOException e) {
  71. e.printStackTrace();
  72. }
  73. }
  74. }
  75. System.out.println("读取:" + string);
  76. return string;
  77. }
  78. }
  79. class UserC {
  80. /**
  81. * 可指定字段序列化顺序,否则按字母顺序(而不是声明顺序)
  82. */
  83. @JSONField(ordinal = 2)
  84. private String username;
  85. @JSONField(ordinal = 1)
  86. private String id;
  87. @JSONField(ordinal = 3)
  88. private String sex;
  89. /**
  90. * 日期类可指定字段序列化格式
  91. */
  92. @JSONField(ordinal = 4,format="yyyy年MM月dd日")
  93. private LocalDate birthday;
  94. public UserC() {}
  95. public UserC(String username, String id, String sex, LocalDate birthday) {
  96. this.username = username;
  97. this.id = id;
  98. this.sex = sex;
  99. this.birthday = birthday;
  100. }
  101. @Override
  102. public String toString() {
  103. return "姓名:"+username+",ID:"+id+",性别:"+sex+",生日:"+birthday;
  104. }
  105. //省略setter和getter方法,项目中记得要补上
  106. }
  107. class UserD {
  108. @JSONField(ordinal = 1)
  109. private String username;
  110. @JSONField(ordinal = 2)
  111. private String id;
  112. @JSONField(ordinal = 3)
  113. private String sex;
  114. public UserD() {}
  115. public UserD(String username, String id, String sex) {
  116. this.username = username;
  117. this.id = id;
  118. this.sex = sex;
  119. }
  120. @Override
  121. public String toString() {
  122. return "姓名:"+username+",ID:"+id+",性别:"+sex;
  123. }
  124. //省略setter和getter方法,项目中记得要补上
  125. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注