Serialization is familiar, but what do we know about it?
Review the old and learn the new, today relearn to comb the knowledge of serialization, people, above!
The outline
We’ll start with the basics of serialization, then we’ll take a look at JSON, and finally we’ll take a look at GSON
Serialization basics
concept
- serialization
The process of converting data structures or objects into binary strings
- deserialization
The process of converting serialized binary strings into data structures or objects
purpose
- serialization
It is used for data transmission and storage on disks for permanent storage
- deserialization
Read byte arrays primarily from disk on the network and restore them to their original objects
Characteristics of the
Just to recap
Versatility, robustness, readability, compatibility and securityCopy the code
Common way
- XML & SOAP
- Protobuf
- JSON
Serialization and persistence
Data persistence can be realized through serialization
Serialization in Android
Serializable
Is a serialization interface provided by Java, Public interface Serializable{} ``` ``` Java public Interface Extranalizable extends Serializable{void writeExternal(ObjectOutput var1) throws IOException; Void readExternal (ObjectInput var1) throw IOException, ClassNotFoundException} ` ` ` * implementation inheritance the Serializable interface ` ` ` Java Public class Student implements Serializable{// Define a serialVersionUID tag private static final Long serialVersionUID=0x23242L; . } ' 'Java public class Student implements Extranalizable{**writeExternal** *readExternal** @override public void writeExternal(ObjectOutput var1) throws IOException; @override public void readExternal(ObjectInput var1) throw IOException,ClassNotFoundException } ```Copy the code
- Serializable implementation principle
Serializable serialization and deserialization are implemented via ObjectOutputStream and ObjectInputStream, respectively
- WriteObject implementation principle
Parcelable
Let’s start with a diagram that shows a data transfer between user space and kernel space for the Parcel application
- implementation
public class Course implements Parcelable{
@override
public int describeContents(a){
return 0;// Return 0
}
// Convert the object to a parcel object
@override
public void writeToParcel(Parcel dest,int flags){}// The implementation class needs to add a Creator attribute for deserialization
public static final Parcelable.Creator<Course> CREATE=new Parcelable.Creator<Course>(){
/ /...}}Copy the code
- conclusion
1.Parcelable is a serialization interface unique to Android, which is more complex than Serializable, but much more efficient than Serializable. 2.Parcelable is provided by Android SDK, which is based on memory. Since the read/write speed of memory is higher than that of hard disk, cross-process object transfer in Android is usually using Parcelable. 3.Parcelable implements read and write methods via Parcel, thus achieving serialization and deserializationCopy the code
JSON related
Let’s start with the familiar JSON data format
{" name ":" Nike ", "number" : 123, "Boolean" : false, "null", null, "array" : {" address ", "China" and "IP" : "192.168.0.1"}}Copy the code
define
JSON(JavaScript Object Natation) is a lightweight data exchange format
role
Data tagging, data storage and data transfer
The characteristics of
1. Fast read and write speed 2. Simple parsing 3. Lightweight 4. It is self-descriptiveCopy the code
grammar
JSON is built in two structures
- Key-value Form of key-value pairs (Object/ dictionary/record)
- An ordered list of values, in array form
Common parsing methods
- moshi (kotlin)
- JackSon
- FastJson
- Org. json comes with Android Studio
It is a document-driven parsing method that first reads all the files into memory and then iterates through all the data to retrieve the desired data as needed
- Gson
Based on event-driven parsing, a JavaBean class corresponding to JSON data is established according to the required data, and then the desired data is parsed through simple operations
Talking about common parsing methods, now let’s talk about a parsing class I often use, GSON
Gson
use
Gson gson=new Gson();
gson.toJson();
gson.fromJson();
// This can also be done by the builder
GsonBuilder.create()
Copy the code
Why don’t I do nothing, just give a bean, and it can parse the data format we want? Now listen to me
parsing
You can visit the JSON official website to learn more about JSON
In fact, when we pass in a JSON string format, it goes through a parsing process. Generally speaking, the parsing process includes two stages of parsing and semantic analysis: parsing json string into a Token stream according to word-formation rules. For example, the following JSON string parsing
{"key","value",}
Copy the code
After word meaning analysis, a set of tokens are obtained as follows:
{key,value,}
Copy the code
After obtaining the Token, a syntax analysis is performed. The purpose of syntax analysis is to check whether the Json format formed in the Token sequence is valid according to the Json format
- conclusion
1. Parse the string into a set of Token sequences using word meaning analysis. 2Copy the code
Now that we know how JSON is structured, we know that Gson does all of this for us internally (a parser role, in plain English), but for learning purposes, it’s important to understand how it works internally
Several commonly used classes
- JsonElements
public abstract class JsonElement {
public abstract JsonElement deepCopy(a);
public boolean isJsonArray(a) {
return this instanceof JsonArray;
}
public boolean isJsonObject(a) {
return this instanceof JsonObject;
}
public boolean isJsonPrimitive(a) {
return this instanceof JsonPrimitive;
}
public boolean isJsonNull(a) {
return this instanceof JsonNull;
}
public JsonObject getAsJsonObject(a) {
if (isJsonObject()) {
return (JsonObject) this;
}
throw new IllegalStateException("Not a JSON Object: " + this);
}
public JsonArray getAsJsonArray(a) {
if (isJsonArray()) {
return (JsonArray) this;
}
throw new IllegalStateException("Not a JSON Array: " + this);
}
public JsonPrimitive getAsJsonPrimitive(a) {
if (isJsonPrimitive()) {
return (JsonPrimitive) this;
}
throw new IllegalStateException("Not a JSON Primitive: " + this);
}
public JsonNull getAsJsonNull(a) {
if (isJsonNull()) {
return (JsonNull) this;
}
throw new IllegalStateException("Not a JSON Null: " + this);
}
public boolean getAsBoolean(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public Number getAsNumber(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public String getAsString(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public double getAsDouble(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public float getAsFloat(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public long getAsLong(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public int getAsInt(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public byte getAsByte(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
@Deprecated
public char getAsCharacter(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public BigDecimal getAsBigDecimal(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public BigInteger getAsBigInteger(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
public short getAsShort(a) {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
@Override
public String toString(a) {
try {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setLenient(true);
Streams.write(this, jsonWriter);
return stringWriter.toString();
} catch (IOException e) {
throw newAssertionError(e); }}}Copy the code
From the source we found that this is an abstract class, it represents a json string element, this element can be a basic type (javaPrimitive), can be null, can be Object, can be Array and other types, in fact, JsonElement provides a set of methods to determine the current type of JsonElement
- TypeAdapter
In Gson, we found that whether the new Gson method or the new GsonBuilder method, we can find the trace of TypeAdapter, rewrite the write method and read to achieve json data conversion operation
public abstract class TypeAdapter<T>{
public abstract void write(JsonWriter out,T value) throws IOException;
public abstract void write(JsonReader in) throws IOException
}
Copy the code
process
Let’s take a quick look at the process
We found that Gson used reflection and generics to obtain the corresponding TypeAdapter by judging the Type of Type and complete a parsing of Json string
Analytical principle
Don’t explain, go straight to the flow chartYou need to know the loading order of the Factory loading order
The exclusion Adapter is loaded first, then the custom TypeAdapter, and finally the basic TypeAdapter
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// users' type adapters
factories.addAll(factoriesToBeAdded);
// type adapters for basic platform typesfactories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.INTEGER_FACTORY); factories.add(TypeAdapters.BOOLEAN_FACTORY); factories.add(TypeAdapters.BYTE_FACTORY); factories.add(TypeAdapters.SHORT_FACTORY); .Copy the code
Reflection principle
Common mistakes
Expected BEGIN_ARRAY but was STRING at line 1 column 27
Copy the code
This kind of error occurs because the data format provided by the server does not meet the REQUIREMENTS of JSON format. Then the problem comes. Is there no solution for this problem?
Of course not. There are two solutions:
- Let return null to solve the problem
- With Gson built-in solution, you can customize JsonDeserializer to handle, rewrite the method inside
public class ErrorJsonDeserializer implements JsonDeserializer<ErroJson>{}// Use the GsonBuilder method to register TypeAdapter
GsonBuilder builder=new GsonBuilder();
builder.registerTypeAdapter(ErrorJson.class,new ErrorJsonDeserializer());
Gson gson=builder.create();
gson.toJson();
Copy the code
The interview questions
- What is a serialVersionUID?
Simply put, serialVersionUID is used to ensure that serialized objects are properly deserialized
- What happens if a member variable in a serializable class does not implement a serializable interface?
In a Serializable class, attributes that do not implement Serializable cannot be serialized and deserialized
- What should I do if I want some members not to be serialized?
Transient keyword TRANSIENT can be added
- What methods are used in Java serialization and de-serialization?
readObject/writeObject
- Why does Android use bundles instead of maps to transfer data?
The inside of the Bundle is implemented by ArrayMap, which consists of two arrays, an int array that stores the subscripts of the object data. An array of objects holds keys and values. Internal dichotomy is used to sort keys, so dichotomy search is adopted in the process of adding, deleting and searching. Therefore, this operation is only applicable to operations with a small amount of data (within 1000 items). If a HashMap operation is used for a large amount of data (the internal structure of a HashMap is an array + linked list), the operation speed of a HashMap operation is slower than that of An ArrayMap operation when a HashMap operation has a small amount of data and occupies a larger memory space than that of An ArrayMap operationCopy the code
- Intents/bundles in Android
Intents deliver data through a binder mechanism. Binder buffers are limited, and a process has 16 binder threads by default, so each thread can occupy a smaller bufferCopy the code
- Why can’t IntEnts pass objects directly between components rather than through serialization?
When an Intent starts another component, it enters the AMS process. This means that the data carried by the Intent needs to be called across processes. Android is based on Linux, and Java objects between different processes cannot be transferred. Therefore, only objects that have been serialized can communicate between applications and AMS processesCopy the code
- Is the serialized object a deep copy or a shallow copy?
Before we answer that question, what is deep copy? What is shallow copy? Shallow copy: creates a new object in the heap, copying the value of the primitive type, but copies the same address of the complex data type, that is, the object. Deep copy: For complex data types, we have a memory address in the heap to store the copied object and to copy the original object over, the two objects are independent of each other, that is, two different addresses and the serialized object is already stored on disk, so it's a deep copyCopy the code
- Is Serializable different from Parcelable?