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?