java中的空接口的疑问

sling2007 2011-04-13 12:01:36
Java如果让某个类的实例具有序列化功能,
需要实现Serializable接口,它只是一个标志,没有任何方法,只有实现这个接口才具有序列化功能。

那么JVM的实现中为什么不让类都有序列化功能呢?而不必继承这个接口?
加一个Seriablizable是不是多此一举了?

====================
搜出一个解释如下,但我还是不理解为什么要加一个空接口..........

可以通过这个标记接口来判断某个类是否可以实现某种功能.
具体判断方法如下
假设类A存在,标志接口Mark
if(Mark.class.isInstance(new A())){....}
...全文
431 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
a490268455 2012-05-03
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]
引用 15 楼 sling2007 的回复:
感谢magicluo这么敬业的做分析,但是我觉得主要用于判断有点牵强,让任何实例序列化不行吗?
我还是疑惑:以序列化接口为例,jdk的设计之初,为什么要这个接口,而不是让每个实例都可以序列化呢?
为什么要用一个接口标志一下?
为什么不用空接口标志一下某个类的实例是否可以用在多线程?用在clone自身?(只是举例,未必恰当)

呵呵,就Ser……
[/Quote]
我知道的Cloneable接口的一个作用是当没有实现Cloneable接口时,使用Object类的clone方法将跑出异常,所以我的理解时:空接口的作用是不是作为判断,用以对某些方法进行限制
caofaping 2011-04-14
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 magicluo 的回复:]
引用 11 楼 caofaping 的回复:
9.10楼

Java code

主要是做判断使用


那不是扯淡么?


可能本人能力有限,到目前为止只知道其序列化功能,


嘴巴放干净点。

别人是说空接口的作用,又没只是说Serializable这一个接口,它只是举例而已。
我也只是帮他一起分析而已..

你唧唧歪歪的叫什么叫啊?
[/Quote]

[Quote=引用 16 楼 guujiang 的回复:]
我看11楼才是在扯淡,空接口恰恰就是作为判断用的
[/Quote]

我错了,又学习了空接口作用(不是Serializable接口作用)主要是用来做判断用的。
magicluo 2011-04-14
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 sling2007 的回复:]
感谢magicluo这么敬业的做分析,但是我觉得主要用于判断有点牵强,让任何实例序列化不行吗?
我还是疑惑:以序列化接口为例,jdk的设计之初,为什么要这个接口,而不是让每个实例都可以序列化呢?
为什么要用一个接口标志一下?
为什么不用空接口标志一下某个类的实例是否可以用在多线程?用在clone自身?(只是举例,未必恰当)[/Quote]

呵呵,就Serializable接口来说,类要去实现序列化有很大的代价,虽然只是简单的实现了这个这么一个标识接口,主要在于:
1. 一旦这个类实现了序列化接口,假如被发布使用,就大大降低了“改变这个类的实现”的灵活性. 因为这个类的字节流编码就变成了它导出API的一部分,一旦这个类被广泛使用,必须的保持这样的形式。使得类的演变收到限制,比如它和序列号UID有直接关系

2. 增加了出现bug和安全漏洞的可能性

3. 使得测试负担加重.

序列化是一个很复杂的问题,要被序列化的类实现标识接口很简单,但在使用ObjectOutputStream类似的流对该对象进行序列化处理时候,是非常繁杂和困难的,考虑的因素非常多...

这也许是为什么不是JDK设计之初不让默认任何对象序列化的原因之一吧,因为即使你标识为该接口声明能序列化,但实际上很多因素在一起 不一定可以,而且带来的问题很多,使得类的扩展性受限.

你可以看看《Effective java中文版(第二版)》第11章74条,详细解释了为什实现序列化接口的谨慎和带来的潜在问题...

看了你就明白。

另外,jdk中也有个Cloneable标识接口,但这个接口实际上作用并没有达到效果。

通常情况下,实现标识接口就是为了表明该类是否属于某中特定的类型,至于符合这样的类型的类,该怎么处理,就看你程序中是如何处理而已。标识下这个类而已.
GuuJiang 2011-04-14
  • 打赏
  • 举报
回复
我看11楼才是在扯淡,空接口恰恰就是作为判断用的
sling2007 2011-04-14
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 magicluo 的回复:]

主要是做判断使用

给你看个简单的例子,你就明白了

Java code

package cn.please.serializable;

import java.io.Serializable;

//实现此标识接口的类,其中不含任何方法
class A implements Serializab……
[/Quote]
感谢magicluo这么敬业的做分析,但是我觉得主要用于判断有点牵强,让任何实例序列化不行吗?
我还是疑惑:以序列化接口为例,jdk的设计之初,为什么要这个接口,而不是让每个实例都可以序列化呢?
为什么要用一个接口标志一下?
为什么不用空接口标志一下某个类的实例是否可以用在多线程?用在clone自身?(只是举例,未必恰当)
  • 打赏
  • 举报
回复
性能损失?这根本就没有性能损失。

不要过多地担心性能,这样种担心纯属杞人忧天!在最新版本的 JDK 中的内存分配性能比 C 中的 malloc 高,像 new 一个对象基本上只要 10 个指令就行了。
sling2007 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 aotian16 的回复:]

jvm要对这些处理的,
对所有类都加上这个功能性能不是下降了吗?
[/Quote]
有这个功能但是不用也没有太多的性能损失吧?
比如Object类中的一些方法,并不是在任何情况下都用的啊.比如wait notify等
那么再在Object中加一个类似的方法不就OK了?
xiaomowen_74839 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 aotian16 的回复:]

jvm要对这些处理的,
对所有类都加上这个功能性能不是下降了吗?
[/Quote]支持一下
aotian16 2011-04-13
  • 打赏
  • 举报
回复
jvm要对这些处理的,
对所有类都加上这个功能性能不是下降了吗?
magicluo 2011-04-13
  • 打赏
  • 举报
回复
主要功能还是表明实现了这个接口的类属于一个特定的类型。

java.io.Serializable和java.rmi.Remote 都是这样子的..

个人使用的话,主要用在工具类中吧。
xiaoxiongzhuzhu 2011-04-13
  • 打赏
  • 举报
回复
在序列化中有一些东西是不能序列化的比如密码之类的,如果都被序列化了就会被黑客查询到,安全性不高了
fafi09 2011-04-13
  • 打赏
  • 举报
回复
个人理解实现空接口一般是,要做本地化处理,jvm判断如果你实现了对应的空接口那么就做相应的本地化处理。
magicluo 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 caofaping 的回复:]
9.10楼

Java code

主要是做判断使用


那不是扯淡么?


可能本人能力有限,到目前为止只知道其序列化功能,
[/Quote]

嘴巴放干净点。

别人是说空接口的作用,又没只是说Serializable这一个接口,它只是举例而已。
我也只是帮他一起分析而已..

你唧唧歪歪的叫什么叫啊?
caofaping 2011-04-13
  • 打赏
  • 举报
回复
9.10楼

主要是做判断使用

那不是扯淡么?


可能本人能力有限,到目前为止只知道其序列化功能,
magicluo 2011-04-13
  • 打赏
  • 举报
回复
帮你看了下ObjectOutputStream 中关于对对象进行序列化写入的方法,如我上所叙述,是使用instanceOf来对执行的类进行类型实例判断的,参考jdk 1.6 中的源码



/**
* 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 接口!!!

其他的源码你自己有空看看,大概就是如此了...
magicluo 2011-04-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 sling2007 的回复:]
那为什么使用空接口啊?达人们
[/Quote]

主要是做判断使用

给你看个简单的例子,你就明白了


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 异常,表明该对象没有实现此接口,不能序列化.

事实上你自己以后进行类的架构设计时,可以考虑类似的方法:
满足实现某一接口的类能被某种操作进行筛选的条件。 你只想知道这个类是符合我的条件而已,我不需要这个类去实现多余的方法,所以标识接口就比较有用了.
sling2007 2011-04-13
  • 打赏
  • 举报
回复
那为什么使用空接口啊?达人们
aotian16 2011-04-13
  • 打赏
  • 举报
回复
我误人子弟了,
mtv0199 2011-04-13
  • 打赏
  • 举报
回复
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:


ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧