-
为什么要序列化?
由于需要在不同的主机中进行数据的传递,而这样的数据需要转换成字节序列方可进行传输。这也就是需要将对象先序列化成字节序列,接收方再进行反序列化将字节序列转换成Java对象。
-
如何进行序列化?
public class SerializableDemo { public static void main(String[] args) throws IOException { StudentSerializable studentSerializable = new StudentSerializable(); studentSerializable.setAge(1); studentSerializable.setName("KKGS"); studentSerializable.setSno("111"); String path = "C:\\Users\\KKGS\\Desktop\\student.txt"; serializable(studentSerializable,path); Object deserializable = deserializable(path); System.out.println(deserializable); } private static void serializable(StudentSerializable studentSerializable,String path) throws IOException { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File(path))); try { objectOutputStream.writeObject(studentSerializable); } catch (IOException e) { e.printStackTrace(); } finally { objectOutputStream.close(); } } private static Object deserializable(String path) throws IOException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File(path))); Object object = null; try { object = objectInputStream.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally { objectInputStream.close(); } return object; } }
-
serializable接口作用
点入该接口发现,该接口是空的,由此可猜想该接口应该属于标记型接口(类是与RandomAccess)用于标记是否应用某种能力,在此将serizable接口实现去掉,找到报错处发现// remaining cases if (obj instanceof String) { writeString((String) obj, unshared); } else if (cl.isArray()) { writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { writeEnum((Enum<?>) obj, desc, unshared); } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } }
若序列化对象非string、array、enum、或者实现serizable接口的将会抛出异常,由此serizable接口并不是进行序列化的实际操作,而是标记该对象可进行序列化。
-
serizable所需的序列号有何用?
用于确保序列化及其反序列化后二者是同一对象。若二者序列号不一致则将不可进行反序列。
若未声明序列号,系统将会为对应对象生成一个一个默认序列号,当类属性改变了序列号也会随之变化,因此为了保证对象的唯一性最好还是显式的将序列号设置。 -
注意!!!!
**对于用 **static
及其transient
修饰的字段是不会被序列化的- 不能序列化static是由于进行序列化时存储的是对象信息,而非类信息,因此static修饰的字段是无法被序列化的。
- 不能序列化transient是以为,被该关键字修饰的字段仅存在于内存之中。(对于敏感字段入密码可使用该关键字修饰,使得在传输时该字段不会被泄露)
-
序列化控制
为了控制由于在数据传输时,中间字节流被窃取并篡改成严重背离真实的值,可以在实体类中新增readObject
方法进行成员变量的约束。private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException { // 默认反序列化函数 objectInputStream.defaultReadObject(); //手工检查 反序列化变量的合法性 if (age < 0 || age > 100){ throw new IllegalArgumentException("年龄必须在0到100之间!!!"); } }
在进行反序列化时,若年龄不在规定的范围内则将抛出异常。在进行反序列化时,ObjectStreamClass会通过反射调用readObject方法,由此若实体中有readObject方法则会被调用。