Java如果让某个类的实例具有序列化功能,
需要实现Serializable接口,它只是一个标志,没有任何方法,只有实现这个接口才具有序列化功能。那么JVM的实现中为什么不让类都有序列化功能呢?而不必继承这个接口?
加一个Seriablizable是不是多此一举了?====================
搜出一个解释如下,但我还是不理解为什么要加一个空接口..........可以通过这个标记接口来判断某个类是否可以实现某种功能.
具体判断方法如下
假设类A存在,标志接口Mark
if(Mark.class.isInstance(new A())){....}
需要实现Serializable接口,它只是一个标志,没有任何方法,只有实现这个接口才具有序列化功能。那么JVM的实现中为什么不让类都有序列化功能呢?而不必继承这个接口?
加一个Seriablizable是不是多此一举了?====================
搜出一个解释如下,但我还是不理解为什么要加一个空接口..........可以通过这个标记接口来判断某个类是否可以实现某种功能.
具体判断方法如下
假设类A存在,标志接口Mark
if(Mark.class.isInstance(new A())){....}
对所有类都加上这个功能性能不是下降了吗?
比如Object类中的一些方法,并不是在任何情况下都用的啊.比如wait notify等
那么再在Object中加一个类似的方法不就OK了?
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
主要是做判断使用给你看个简单的例子,你就明白了
package cn.please.serializable;import java.io.Serializable;//实现此标识接口的类,其中不含任何方法
class A implements Serializable {}// 类B没有实现Serializable接口
class B {
}public class Test {
public static void main(String[] args) { A a = new A();
B b = new B(); // A的实例对象 a 同样可以作为是Serializable类型 ,类B则不行
System.out.println(a instanceof Serializable); //output: true
System.out.println(b instanceof Serializable); //output: false
}}java在进行序列化操作时候,会用类似instanceOf (具体怎么样的不清楚,你可以参考源码看看,只是推测)的方法来检查要序列化的对象是否实现了serializable接口 ,如果没有实现 则会抛出NotSerializableException 异常,表明该对象没有实现此接口,不能序列化.事实上你自己以后进行类的架构设计时,可以考虑类似的方法:
满足实现某一接口的类能被某种操作进行筛选的条件。 你只想知道这个类是符合我的条件而已,我不需要这个类去实现多余的方法,所以标识接口就比较有用了.
* Underlying writeObject/writeUnshared implementation.
*/
private void writeObject0(Object obj, boolean unshared)
throws IOException
{
//以下源码摘抄自1142行起
// remaining cases
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) { //这里对需要进行序列化的对象instanceOf判断,也就是判断该对象有没有实现标识接口Serializable
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}
在源码部分,为什么判断了 obj instanceOf Stirng ,Enum类型 他也执行序列化操作呢?
因为String和 Enum 自己本身实现了Serializable 接口!!!其他的源码你自己有空看看,大概就是如此了...
嘴巴放干净点。别人是说空接口的作用,又没只是说Serializable这一个接口,它只是举例而已。
我也只是帮他一起分析而已..你唧唧歪歪的叫什么叫啊?
我还是疑惑:以序列化接口为例,jdk的设计之初,为什么要这个接口,而不是让每个实例都可以序列化呢?
为什么要用一个接口标志一下?
为什么不用空接口标志一下某个类的实例是否可以用在多线程?用在clone自身?(只是举例,未必恰当)
呵呵,就Serializable接口来说,类要去实现序列化有很大的代价,虽然只是简单的实现了这个这么一个标识接口,主要在于:
1. 一旦这个类实现了序列化接口,假如被发布使用,就大大降低了“改变这个类的实现”的灵活性. 因为这个类的字节流编码就变成了它导出API的一部分,一旦这个类被广泛使用,必须的保持这样的形式。使得类的演变收到限制,比如它和序列号UID有直接关系2. 增加了出现bug和安全漏洞的可能性3. 使得测试负担加重.序列化是一个很复杂的问题,要被序列化的类实现标识接口很简单,但在使用ObjectOutputStream类似的流对该对象进行序列化处理时候,是非常繁杂和困难的,考虑的因素非常多...这也许是为什么不是JDK设计之初不让默认任何对象序列化的原因之一吧,因为即使你标识为该接口声明能序列化,但实际上很多因素在一起 不一定可以,而且带来的问题很多,使得类的扩展性受限.你可以看看《Effective java中文版(第二版)》第11章74条,详细解释了为什实现序列化接口的谨慎和带来的潜在问题... 看了你就明白。另外,jdk中也有个Cloneable标识接口,但这个接口实际上作用并没有达到效果。通常情况下,实现标识接口就是为了表明该类是否属于某中特定的类型,至于符合这样的类型的类,该怎么处理,就看你程序中是如何处理而已。标识下这个类而已.