一起养成写作习惯!这是我参与「日新计划 4 月更文挑战」的第2天,点击查看活动详情。

序列化

Parcelable vs Serializable  序列化

将实例的状态转换为可以存储或传输的形式的过程。

Objecandroid是什么手机牌子tOutputStream

构造函数

public ObjectOutputStream(OutputStream out) throws IOException {
    verifySubclass();
    bout = new BlockDataOutputStream(out);//用于写入文件的Stream
    handles = new HandleTable(10, (float) 3.00);
    subs = new ReplaceTable(10, (float) 3.00);
    enableOverride = false;
    writeStreamHeader(); //开始写入魔数和版本号
    bout.setBlockDataMode(true);
    if (extendedDebugInfo) {
        debugInfoStack = new DebugTraceInfoStack();
    } else {
        debugInfoStack = null;
    }
}

write二进制Object方法

public final void writeObject(Object obj) throws IOException {
    if (enableOverride) {
        writeObjectOverride(obj);
        return;
    }
    try {
        writeObject0(obj, false);
    } catch (IOException ex) {
        if (depth == 0) {
            try {
                writeFatalException(ex);
            } catch (IOException ex2) {
            }
        }
        throw ex;
    }
}

调用writeObject0方法

  private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
           。。。
           //创建出来一个原始数据的描述信息的实例
          desc = ObjectStreamClass.lookup(cl, true);
           。。。
         //根据类型信息将实例信息写入输出流
        if (obj instanceof Class) {
            writeClass((Class) obj, unshared);
        } else if (obj instanceof ObjectStreamClass) {
            writeClassDesc((ObjectStreamClass) obj, unshared);
        // END Android-changed: Make Class and ObjectStreamClass replaceable.
        } else 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());
            }
        }
    }

ObjectStreamClass的创建过程

static ObjectStreamClass lookup(Class<?> cl, boolean all) {
    ...
    Reference<?> ref = Caches.localDescs.get(key);//读取缓存
    Object entry = null;
    if (ref != null) {
        entry = ref.get();
    }
    EntryFuture future = null;
    if (entry == null) {
        EntryFuture newEntry = new EntryFuture();
        Reference<?> newRef = new SoftReference<>(newEntry);
        do {
            if (ref != null) {
                Caches.localDescs.remove(key, ref);
            }
            ref = Caches.localDescs.putIfAbsent(key, newRef);
            if (ref != null) {
                entry = ref.get();
            }
        } while (ref != null && entry == null);
        if (entry == null) {
            future = newEntry;
        }
    }
    if (entry instanceof ObjectStreamClass) {  // check common case first
        return (ObjectStreamClass) entry;
    }
    if (entry instanceof EntryFuture) {
        future = (EntryFuture) entry;
        if (future.getOwner() == Thread.currentThread()) {
            entry = null;
        } else {
            entry = future.get();
        }
    }
    //没有缓存的情况
    if (entry == null) {
        try {
            entry = new ObjectStreamClass(cl);
        } catch (Throwable th) {
            entry = th;
        }
        if (future.set(entry)) {
            Caches.localDescs.put(key, new SoftReference<Object>(entry));
        } else {
            entry = future.get();
        }
    }
    if (entry instanceof ObjectStreamClass) {
        return (ObjectStreamClass) entry;
    } else if (entry instanceof RuntimeException) {
        throw (RuntimeException) entry;
    } else if (entry instanceof Error) {
        throw (Error) entry;
    } else {
        throw new InternalError("unexpected entry: " + entry);
    }
}

进入ObjectStreamClass构造函数

private ObjectStreamClass(final Class<?> cl) {
    this.cl = cl;
    ...
    name = cl.getName();//反射获取
    isProxy = Proxy.isProxyClass(cl);
    isEnum = Enum.class.isAssignableFrom(cl);
    serializable = Serializable.class.isAssignableFrom(cl);
    externalizable = Externalizable.class.isAssignableFrom(cl);
    Class<?> superCl = cl.getSuperclass();
    superDesc = (superCl != null) ? lookup(superCl, false) : null;
    ...
    suid = getDeclaredSUID(cl);
    fields = getSerialFields(cl);
    computeFieldOffsets();
    initialized = true;
}

读取属性中使用反射

private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
    Field[] clFields = cl.getDeclaredFields();
    ArrayList<ObjectStreamField> list = new ArrayList<>();
    int mask = Modifier.STATIC | Modifier.TRANSIENT;
    for (int i = 0; i < clFields.length; i++) {
        if ((clFields[i].getModifiers() & mask) == 0) {
            list.add(new ObjectStreamField(clFields[i], false, true));
        }
    }
    int size = list.size();
    return (size == 0) ? NO_FIELDS :
        list.toArray(new ObjectStreamField[size]);
}

Parcelablkotlin面试题e

Parcelable vs Serializable  序列化

Kotlin 有一个Parceliz二进制亡者列车e注解可以帮我们生成实现Parcelable之后需要写的代码

  • kotlin怎么读象自行实现出入口方法,避免对类结构的反射
  • 二进制流存储在连续内存中,占用空间更小
  • 牺牲易用性(可以通过Parcelize弥补),换取极致的性能

Serializable

  • 用反射获取类的结构和属性信息,过程中会产生中间信息
  • 有缓存结构,在解析相同类型的情况下,能复用缓存
  • 性能在二进制转换器可接受的范围内,易用性比较好

Intent传值场景

进入Pjava模拟器arcel.java类中的writeSerializable

Serializable是先通过ObjectOutp二进制转化为十进制utStream,把对象转成ByteArray,再通过writeByteArray写入Parcel

public final void writeSerializable(@Nullable Serializable s) {
    if (s == null) {
        writeString(null);
        return;
    }
    String name = s.getClass().getName();
    writeString(name);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(s);
        oos.close();
        writeByteArray(baos.toByteArray());
    } catch (IOException ioe) {
        throw new RuntimeException("Parcelable encountered " +
            "IOException writing serializable object (name = " + name +
            ")", ioe);
    }
}

Parcelable 调用对象内部实现的writeToParcel方法中的逻辑,通过一些write方法直接写入Parcel

public static void writeToParcel(@Nullable CharSequence cs, @NonNull Parcel p,
        int parcelableFlags) {
    if (cs instanceof Spanned) {
        p.writeInt(0);
        p.writeString8(cs.toString());
        Spanned sp = (Spanned) cs;
        Object[] os = sp.getSpans(0, cs.length(), Object.class);
        for (int i = 0; i < os.length; i++) {
            Object o = os[i];
            Object prop = os[i];
            if (prop instanceof CharacterStyle) {
                prop = ((CharacterStyle) prop).getUnderlying();
            }
            if (prop instanceof ParcelableSpan) {
                final ParcelableSpan ps = (ParcelableSpan) prop;
                final int spanTypeId = ps.getSpanTypeIdInternal();
                if (spanTypeId < FIRST_SPAN || spanTypeId > LAST_SPAN) {
                    Log.e(TAG, "External class "" + ps.getClass().getSimpleName()
                            + "" is attempting to use the frameworks-only ParcelableSpan"
                            + " interface");
                } else {
                    p.writeInt(spanTypeId);
                    ps.writeToParcelInternal(p, parcelableFlags);
                    writeWhere(p, sp, o);
                }
            }
        }
        p.writeInt(0);
    } else {
        p.writeInt(1);
        if (cs != null) {
            p.writeString8(cs.toString());
        } else {
            p.writeString8(null);
        }
    }
}

由于ObjectSt二进制计算器reamClass存在缓存机制,在一次序列化过程中,如果涉及大量相同类的不同实例化,Serializable的性能会存在优势。