Premise: CopyOnWriteArrayList can be serialized, and its internal elements will also be serialized. Therefore, it triggered the consideration of TRANSIENT: “Whether transient keyword modifies variables can be serialized”
Transient keyword
1. The first impression of transient keyword: the variable modified by it cannot be serialized (as verified by the following example)
Entity
public class TestStream implements Serializable {
private String id;
private transient String name;
private transient volatile Object[] array;
private transient Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object[] getArray() {
return array;
}
public void setArray(Object[] array) {
this.array = array;
}
@Override
public String toString() {
return "TestStream{" +
"id='" + id + '\'' + "age='" + age + '\'' + ", name='" + name + '\' ' +
", array=" + Arrays.toString(array) +
'} ';
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) { this.age = age; }}Copy the code
TestClass
@Test
public void testSeri() throws Exception {// Tests serializing TestStreamtestStream = new TestStream();
testStream.setId("123");
testStream.setName("QBH");
testStream. SetArray (new Object [] {1, 2, 3});testStream.setAge(18);
System.out.println(testStream); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(testStream); ByteArrayInputStream bi = new ByteArrayInputStream(bo.tobyteArray ()); ObjectInputStream oi = new ObjectInputStream(bi); TestStream object1 = (TestStream)oi.readObject(); System.out.println(object1); }Copy the code
Result
TestStream{id= age name array is a transient variable that is not serialized'007'age='18', name='juejin', array=[1, 2, 3]}
TestStream{id='007'age='null', name='null', array=null}
Copy the code
WriteObject and readOject
WirteObject method
This method is called when the object “overrides” it for serialization (reflection is used to check for overrides). Knowing when a method is called, you know what it’s for: custom serialization steps
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{}
Copy the code
This method is called when the object “overrides” the deserialization (reflection is used to check for overrides) purpose: Customize the deserialization step
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException{}
Copy the code
example
Entity: rewrite the writeObject and readObject methods (CopyOnwriteArrayList also rewritten, cpoy to come over for some of the properties of custom sequence | deserialization)
package entity; import java.io.Serializable; import java.util.Arrays; import sun.misc.SharedSecrets; public class TestStream implements Serializable { private String id; private transient String name; private transient volatile Object[] array; // Consistent with CopyOnWriteArrayList array private TRANSIENT Integer AGE; public StringgetId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object[] getArray() {
return array;
}
public void setArray(Object[] array) {
this.array = array;
}
@Override
public String toString() {
return "TestStream{" +
"id='" + id + '\'' + "age='" + age + '\'' + ", name='" + name + '\' ' +
", array=" + Arrays.toString(array) +
'} ';
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) { this.age = age; } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); Object[] elements = getArray(); // Write out array length s.writeInt(elements.length); // Serialize the length of the array. // Serialize age attributes // Write out all elementsin the proper order.
for (Object element : elements)
s.writeObject(element);
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); int len = s.readInt(); // Read the length of arraysetAge(s.readInt()); / / read the value of the age SharedSecrets. GetJavaOISAccess () checkArray (s, Object [] class, len); Object[] elements = new Object[len]; // Readin all elements in the proper order.
for (int i = 0; i < len; i++)
elements[i] = s.readObject();
setArray(elements); }}Copy the code
TestClass
@Test
public void testSeri() throws Exception {// Tests serializing TestStreamtestStream = new TestStream();
testStream.setId("123");
testStream.setName("QBH");
testStream. SetArray (new Object [] {1, 2, 3});testStream.setAge(18);
System.out.println(testStream); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(testStream); ByteArrayInputStream bi = new ByteArrayInputStream(bo.tobyteArray ()); ObjectInputStream oi = new ObjectInputStream(bi); TestStream object1 = (TestStream)oi.readObject(); System.out.println(object1); }Copy the code
Result
TestStream{id='007'age='18', name='juejin', array=[1, 2, 3]}
TestStream{id='007'age='18', name='null', array=[1, 2, 3]}
Copy the code
conclusion
So it is not true that transient attributes cannot be serialized. However, the write and read attributes must correspond to each other in order to avoid serialization errors
thinking
Why does CopyOnWriteArrayList make array transient and then serialize writeObject and readObject?
: Because the array of CopyOnWriteArrayList is a “tuple”, the size of the array is usually not equal to the actual number of elements, so to avoid the problem of the number of elements in the array when deserialization (write a simple version of the List to test), so rewrite the serialization step.
This article deals with serialization knowledge is very shallow, only introduces how to customize serialization, if you want to learn more about serialization, can debug source tracing