当前位置:  开发笔记 > 编程语言 > 正文

Java中的Serializable和Externalizable有什么区别?

如何解决《Java中的Serializable和Externalizable有什么区别?》经验,为你挑选了8个好方法。

SerializableExternalizableJava有什么区别?



1> skaffman..:

要添加其他答案,通过实现java.io.Serializable,您可以获得类的对象的"自动"序列化功能.不需要实现任何其他逻辑,它只会工作.Java运行时将使用反射来确定如何编组和解组对象.

在早期版本的Java中,反射非常慢,因此序列化大对象图(例如在客户端 - 服务器RMI应用程序中)是一个性能问题.为了处理这种情况,java.io.Externalizable提供了接口,它就像java.io.Serializable使用自定义编写的机制来执行编组和解组功能(您需要在类上实现readExternalwriteExternal方法).这为您提供了解决反射性能瓶颈的方法.

在Java的最新版本(当然是1.3版本)中,反射的性能比以前要好得多,因此这不是一个问题.我怀疑你很难从Externalizable现代JVM中获得有意义的好处.

此外,内置的Java序列化机制并不是唯一的,您可以获得第三方替换,例如JBoss Serialization,它更快,并且是默认的替代品.

一个很大的缺点Externalizable是你必须自己维护这个逻辑 - 如果你在类中添加,删除或更改一个字段,你必须改变writeExternal/ readExternal方法来解释它.

总之,Externalizable是Java 1.1天的遗物.实在没有必要了.


不根据这些基准:[http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking],说明书的序列化(使用externizable)多,比使用Java的默认序列化更快.如果速度对您的工作很重要,那么一定要编写自己的序列化器.
为什么不能清楚这些答案是Javadoc的一部分?
必须自己维护逻辑只是一个缺点,如果类永远不会改变,你永远不必阅读旧数据的持久版本.如果你想要自由改变你的类而不必编写地狱般的代码来反序列化它的旧版本,``Externalizable``有助于_a lot_.
更新到@Jack建议的新链接https://github.com/eishay/jvm-serializers/wiki/
https://github.com/eishay/jvm-serializers/wiki中的"java-manual"确实*不*使用Externalizable,这意味着使用ObjectOutputStream.有关代码的链接,请参阅https://github.com/eishay/jvm-serializers/wiki/ToolBehavior.相反,它是使用DataOutputStream的手写代码,因此它不会受到使ObjectOutputStream变慢(例如跟踪对象实例和支持对象循环)的影响.
我只需要编写一个自定义集合,我不得不说`Externalizable'更适合我,因为我不想输出带空格或占位符对象的数组,再加上显式接口你可以处理继承,这意味着我的synchronized子类可以很容易地在调用`writeExternal()`时添加锁定.所以是的,Externalizable仍然非常相关,当然对于大型或复杂的对象.

2> Trying..:

序列化提供了存储和稍后重新创建对象的默认功能.它使用详细格式来定义要存储的对象的整个图形,例如假设您有一个linkedList并且您的代码如下所示,那么默认序列化将发现所有链接并将序列化的对象.在默认序列化中,对象完全由其存储的位构成,没有构造函数调用.

  ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("/Users/Desktop/files/temp.txt"));
        oos.writeObject(linkedListHead); //writing head of linked list
        oos.close();

但是,如果您想要限制序列化或者不希望序列化某些对象,请使用Externalizable.Externalizable接口扩展了Serializable接口,并添加了两个方法,writeExternal()和readExternal().这些在序列化或反序列化时自动调用.在使用Externalizable时,我们应该记住默认构造函数应该是public,否则代码将抛出异常.请按照以下代码:

public class MyExternalizable implements Externalizable
{

private String userName;
private String passWord;
private Integer roll;

public MyExternalizable()
{

}

public MyExternalizable(String userName, String passWord, Integer roll)
{
    this.userName = userName;
    this.passWord = passWord;
    this.roll = roll;
}

@Override
public void writeExternal(ObjectOutput oo) throws IOException 
{
    oo.writeObject(userName);
    oo.writeObject(roll);
}

@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException 
{
    userName = (String)oi.readObject();
    roll = (Integer)oi.readObject();
}

public String toString()
{
    StringBuilder b = new StringBuilder();
    b.append("userName: ");
    b.append(userName);
    b.append("  passWord: ");
    b.append(passWord);
    b.append("  roll: ");
    b.append(roll);

    return b.toString();
}
public static void main(String[] args)
{
    try
    {
        MyExternalizable m  = new MyExternalizable("nikki", "student001", 20);
        System.out.println(m.toString());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
        oos.writeObject(m);
        oos.close();

        System.out.println("***********************************************************************");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
        MyExternalizable mm = (MyExternalizable)ois.readObject();
        mm.toString();
        System.out.println(mm.toString());
    } 
    catch (ClassNotFoundException ex) 
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(IOException ex)
    {
        Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
    }
}
}

在这里,如果您对默认构造函数进行注释,那么代码将抛出异常:

 java.io.InvalidClassException: javaserialization.MyExternalizable;     
 javaserialization.MyExternalizable; no valid constructor.

我们可以观察到,由于密码是敏感信息,所以我没有在writeExternal(ObjectOutput oo)方法中对其进行序列化,也没有在readExternal(ObjectInput oi)中设置它的值.这是Externalizable提供的灵活性.

上述代码的输出如下:

userName: nikki  passWord: student001  roll: 20
***********************************************************************
userName: nikki  passWord: null  roll: 20

我们可以观察到因为我们没有设置passWord的值所以它是null.

通过将密码字段声明为瞬态也可以实现相同的目的.

private transient String passWord;

希望能帮助到你.如果我犯了任何错误,我道歉.谢谢.



3> Benjamin Woo..:

为了完整起见,transient关键字也缩小了两者之间的差距.

如果您只想序列化对象的一部分,只需将特定字段设置为transient,将它们标记为不持久化并实现Serializable.


这怎么回事?

4> Ravindra bab..:

Serializable和之间的主要区别Externalizable

    标记界面:Serializable是没有任何方法的标记界面.Externalizable接口包含两种方法:writeExternal()readExternal().

    序列化过程:将为实现Serializable接口的类启动默认序列化过程.程序员定义的序列化过程将为实现Externalizable接口的类启动.

    维护:不兼容的更改可能会破坏序列化.

    向后兼容性和控制:如果您必须支持多个版本,则可以完全控制Externalizable界面.您可以支持对象的不同版本.如果您实施Externalizable,则您有责任序列化super课程

    public No-arg构造函数: Serializable使用反射构造对象,不需要arg构造函数.但Externalizable要求公开的非参数构造函数.

请参阅博客通过Hitesh Garg更多的细节.



5> Uri..:

序列化使用某些默认行为来存储并稍后重新创建对象.您可以指定处理引用和复杂数据结构的顺序或方式,但最终归结为使用每个原始数据字段的默认行为.

外部化在极少数情况下用于您真正想要以完全不同的方式存储和重建对象,而不使用数据字段的默认序列化机制.例如,假设您拥有自己独特的编码和压缩方案.


我们将Externalizable用于大量"选定ID"集合 - 与默认序列化相比,它更有效地外部化为一个或多或少一个原始整数.这是一个非常简单的用例,没有"特殊"或"独特".

6> Yash..:

对象序列化使用Serializable和Externalizable接口. Java对象只能序列化.如果一个类或它的任何超类实现java.io.Serializable接口或其子接口java.io.Externalizable.大多数java类都是可序列化的.

NotSerializableException:packageName.ClassName«要在序列化过程中参与类对象,该类必须实现Serializable或Externalizable接口.

在此输入图像描述


可序列化接口

对象序列化生成一个流,其中包含有关正在保存的对象的Java类的信息.对于可序列化对象,即使存在类的实现的不同(但兼容)版本,也会保留足够的信息来恢复这些对象.Serializable接口定义为标识实现可序列化协议的类:

package java.io;

public interface Serializable {};

序列化接口没有方法或字段,仅用于标识可序列化的语义.对于序列化/反序列化类,要么我们可以使用默认的writeObject和readObject方法(或),我们可以从类中重写writeObject和readObject方法.

JVM将完全控制序列化对象.使用transient关键字来阻止数据成员被序列化.

这里可串行化的对象直接从流中重建而不执行

InvalidClassException«在反序列化过程中,如果本地类serialVersionUID值与相应的发送者类不同.然后结果是冲突的 java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771

类的非瞬态和非静态字段的值被序列化.

可外部化的界面

对于Externalizable对象,容器只保存对象类的标识; 该类必须保存和恢复内容.Externalizable接口定义如下:

package java.io;

public interface Externalizable extends Serializable
{
    public void writeExternal(ObjectOutput out)
        throws IOException;

    public void readExternal(ObjectInput in)
        throws IOException, java.lang.ClassNotFoundException;
}

Externalizable接口有两个方法,一个可外化的对象必须实现一个writeExternal和readExternal方法来保存/恢复一个对象的状态.

程序员必须处理要序列化的对象.作为一个程序员来处理序列化所以,这里的transient关键字不会限制序列化过程中的任何对象.

重构Externalizable对象时,使用public no-arg构造函数创建实例,然后调用readExternal方法.通过从ObjectInputStream中读取可序列化对象来恢复它们.

OptionalDataException« 我们写出来时,这些字段必须是相同的顺序和类型.如果流中存在任何类型不匹配,则抛出OptionalDataException.

@Override public void writeExternal(ObjectOutput out) throws IOException {
    out.writeInt( id );
    out.writeUTF( role );
    out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    this.id = in.readInt();
    this.address = (Address) in.readObject();
    this.role = in.readUTF();
}

写入(公开)ObjectOutput获取序列化的类的实例字段.


示例« implements Serializable

class Role {
    String role;
}
class User extends Role implements Serializable {

    private static final long serialVersionUID = 5081877L;
    Integer id;
    Address address;

    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }
}

class Address implements Serializable {

    private static final long serialVersionUID = 5081877L;
    String country;
}

示例«实现Externalizable

class User extends Role implements Externalizable {

    Integer id;
    Address address;
    // mandatory public no-arg constructor
    public User() {
        System.out.println("Default Constructor get executed.");
    }
    public User( String role ) {
        this.role = role;
        System.out.println("Parametarised Constructor.");
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt( id );
        out.writeUTF( role );
        out.writeObject(address);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.id = in.readInt();
        this.address = (Address) in.readObject();
        this.role = in.readUTF();
    }
}

public class CustomClass_Serialization {
    static String serFilename = "D:/serializable_CustomClass.ser";

    public static void main(String[] args) throws IOException {
        Address add = new Address();
        add.country = "IND";

        User obj = new User("SE");
        obj.id = 7;
        obj.address = add;

        // Serialization
        objects_serialize(obj, serFilename);
        objects_deserialize(obj, serFilename);

        // Externalization
        objects_WriteRead_External(obj, serFilename);
    }

    public static void objects_serialize( User obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        // java.io.NotSerializableException: com.github.objects.Address
        objectOut.writeObject( obj );
        objectOut.flush();
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");
    }
    public static void objects_deserialize( User obj, String serFilename ) throws IOException{
        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            User user = (User) readObject;
            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            User user = new User();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            user.readExternal(ois);

            System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);

            Address add = (Address) user.address;
            System.out.println("Inner Obj : "+ add.country );
            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

@看到

什么是对象序列化

对象序列化:常见问题解答



7> alphazero..:

https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html

默认序列化有点冗长,并假定序列化对象的最广泛使用场景,因此默认格式(Serializable)使用有关序列化对象的类的信息来注释结果流.

外部化使对象流的生产者完全控制精确的类元数据(如果有的话),超出了类的最小必需标识(例如其名称).这在某些情况下显然是可取的,例如封闭环境,其中对象流的生产者及其消费者(从流中对对象进行统一)被匹配,并且关于该类的附加元数据没有用处并且降低性能.

另外(如Uri所指出的)外化还提供对与Java类型相对应的流中的数据的编码的完全控制.对于(一个人为的)示例,您可能希望将布尔值true记录为"Y",将false记录为"N".外化可以让你这样做.



8> 小智..:

实际上并未提供Externalizable接口来优化序列化过程的性能!但是提供实现自己的自定义处理的方法,并提供对对象及其超类型的流的格式和内容的完全控制!

这方面的示例是实现AMF(ActionScript消息格式)远程处理以通过网络传输本机动作脚本对象.

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有