继承是在子类对象中持有一个指向父类对象的引用,super。也就是说,在Java内部,继承是通过隐式的组合实现的。在实际的方法调用中,java会优先在当前类对象中寻找名称相同的方法,如果没有,进而根据super引用到父类对象中去寻找,所以,如果父类方法在子类中得到重写,java会调用子类的方法,而不会调用被重写的父类方法,这也是多态的实现机制。(如果基类和派生类有同名的成员变量,多态机制下取的是基类的成员变量值,成员变量没有重写的概念?)
对象作为参数传递,其实只是传递对象的引用(指针)。
到这里,基本就明白了,内存传来传去的都是地址而已。
跨进程通讯,网络传输,传递对象,(对象是内存中的一个地址引用,跨进程,跨网络,是无法取到的,所以需要序列化、反序列化)
1、序列化作用:
- 持久化存储,保持到本地存储介质
- 网络传输
- IPC(Inner-process communication)进程间传递
Android中序列化和反序列化的方式:实现Serializable和parcelable接口
2、Serializable接口
是Java提供的一种序列化方式
- 序列化之前和反序列化之后的对象不是同一个对象,值一样
- 序列化时,只对对象的状态进行保存,而不管对象的方法
- 当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口
- 当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化
- Serializable通过Transient关键字修饰的字段,不进行序列化,反序列化取出来的是默认值(null/0/false)
- 序列化的时候会产生大量的临时变量,从而引起频繁的GC。
- 适用于持久化存储、数据库、网络流传递
序列化时,通过 ObjectOutputStream 将对象直接输出存储到本地,需要用的时候,通过反射新建一个对象,然后通过 ObjectInputStream 从本地读取流,给对象的每一个field赋值。相当于创建了一个新对象,值一样。
参考:
java基础---->Serializable的使用
java高级---->Serializable的过程分析
拓展:
Java对象序列化为什么要使用SerialversionUID?
- SerialversionUID作为唯一ID,进行序列化和反序列化的参照
- 如果没有指定SerialversionUID,系统会自动生成一个SerialversionUID(和类强相关)
- 反序列化时,如果类发生了改变,会抛出InvalidClassException
- 所以强烈建议用户自定义一个SerialversionUID
3、Parcelable接口
既然有了serializable接口,为什么android还要单独设计Parcelable接口呢?
因为serializable是通过流的方式,频繁读写,会创建很多的临时变量,效率不高。设计出来Parcelable接口,基于Android平台的特性,用于Android不同组件之间的通讯,以及不同进程之间的通讯。
Android开发的时候,Intent在启动其他组件时,会离开当前应用程序进程,进入ActivityManagerService进程(intent.prepareToLeaveProcess()),这也就意味着,Intent所携带的数据要能够在不同进程间传输。Android是基于Linux系统,不同进程之间的java对象是无法传输,所以我们此处要对对象进行序列化,从而实现对象在 应用程序进程 和 ActivityManagerService进程之间传输。
Android系统用户空间不共享内存,内核控件是共享内存的。
parcelable实现原理是在内核空间开辟一块共享内存,序列化和反序列化都是操作这一块的数据。
- 整个读写全是在内存中进行,所以效率比Serializable高
- 不能使用在要将数据存储在磁盘上的情况,只适用于内存传递(IPC)