1)通过网络传输的对象,必须实现Serializable接口,或者父类已经实现序列化接口。
(2)网络传输对象封装太多层次的父类不太好,或者说在interface上用父类定义,然后将子类实例传递给网络另一端的应用可能没这个 jar包/class,反序列化不了的。另一可能情况,动态代理接口InvocationHandler invoke(Object proxy, Method method, Object[] args),传进时,method的参数定义匹配interface上的method参数定义,比如是父类,从args获取的class是子类,如果某种 rpc技术处理不当,或无从识别,困扰的是使用者。
(3)网络接口上的参数、返回值类型、会抛出的异常类,都要实现序列化接口。包括层层里面装着的内容,父类(比较少人对这field推敲private/protected,父类可能有直接被使用的时候)。
(4)ArrayList.subList()返回的List实现类是内部类型,不能序列化的,通过网络传输会出错。
(5)网络对象第一次上线使用时,就要设定serialVersionUID,不要不顾编译警告
网络对象的匹配,除了靠类名,还靠serialVersionUID,serialVersionUID在《Java语言规范》有固定算法,跟各field的定义相关,如果没有显式赋值,虽然看不见,但会底下会默认算出一个进行网络传输。
如果没有显式赋值,也在你看不见觉察不到的情况下,在你增减了field/修改了定义的情况下,serialVersionUID已被改 变,这时网络两端就对接不上而悲剧了。没定义serialVersionUID,而又发生了serialVersionUID变化,网络两端只有所有机器 都停掉,并且先后起有顺序时,才能不出丝毫差错。
(6)网络传输对象要有无参构造器,因为机器系统是不知道传什么内容给有参构造器进行实例化,无参构造器不是public都没关系。没定义无参构造器,有些序列化方式会在底下生成无参构造器的方式才能解决问题。
(7)网络传输最好不要用enum类型,太强耦合,从网络一端传到另一端,对方可能还是旧版本而识别不了。别人文章里有enum的序列化说明
(8)有的人喜欢用1L作为serialVersionUID,但不知道是否是通配值,一开始就有赋值肯定没错,0L对于java enum的序列化有特殊意义。
(9)看看HashMap、Date的源代码,不需通过网络传输的field用transient定义,然后实现writeObject等方法。不是所有场合都识别Externalizable,或许都要此场合特别支持Externalizable才行。
(10)有些系列化格式,遇到反序列化不了的类,会反序列化成Map,但会在使用时遇到class cast异常。
(11)不用抛客户端没有jar的异常类到客户端
(12)同一应用不要有同package同名类,即使隐藏在同名/不同名/不同版本的jar中。
(13)远程调用、分布式调用,分布式缓存等,或许都需要经过序列化,虽然让你透明地使用网络/感觉不到。
(14)不要序列化大数据对象/十分复杂对象,一般long/int/String/Map/List/Array等常见类组成的对象就已能解决问题,最好不要在本应用的业务接口传递/返回另一人主导业务/结构的对象。 不是建议不要用ArrayList,只是要注意ArrayList经过网络后可能顺序不一样。两需一一对应的List,经过网络后不一定一一对应。List中有零星的null,可能会给别人造成麻烦。