Java中可序列化和可外部化的区别是什么?

Java中可序列化和可外部化的区别是什么?,java,serialization,serializable,externalizable,Java,Serialization,Serializable,Externalizable,与在Java中的区别是什么?序列化使用某些默认行为来存储和稍后重新创建对象。您可以指定以什么顺序或如何处理引用和复杂的数据结构,但最终归结为对每个基本数据字段使用默认行为 在极少数情况下,如果确实希望以完全不同的方式存储和重建对象,并且不使用数据字段的默认序列化机制,则会使用外部化。例如,假设您有自己独特的编码和压缩方案 默认序列化有点冗长,并且假设序列化对象的使用场景尽可能广泛,因此默认格式(可序列化)使用有关序列化对象类的信息注释结果流 外部化使对象流的生产者能够完全控制精确的类元数据(如

与在Java中的区别是什么?

序列化使用某些默认行为来存储和稍后重新创建对象。您可以指定以什么顺序或如何处理引用和复杂的数据结构,但最终归结为对每个基本数据字段使用默认行为

在极少数情况下,如果确实希望以完全不同的方式存储和重建对象,并且不使用数据字段的默认序列化机制,则会使用外部化。例如,假设您有自己独特的编码和压缩方案

默认序列化有点冗长,并且假设序列化对象的使用场景尽可能广泛,因此默认格式(可序列化)使用有关序列化对象类的信息注释结果流

外部化使对象流的生产者能够完全控制精确的类元数据(如果有的话),而不仅仅是类的最小标识(例如名称)。在某些情况下,这显然是可取的,例如在封闭环境中,对象流的生产者和其消费者(从流中具体化对象)是匹配的,关于类的附加元数据没有任何用途,并且会降低性能


此外(正如Uri指出的),外部化还提供了对与Java类型对应的流中的数据编码的完全控制。例如,您可能希望将布尔值true记录为“Y”,将布尔值false记录为“N”。外部化允许您这样做。

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

在Java的早期版本中,反射速度非常慢,因此序列化大型对象图(例如在客户机-服务器RMI应用程序中)有点性能问题。为了处理这种情况,提供了
java.io.Externalizable
接口,它类似于
java.io.Serializable
,但具有自定义的编写机制来执行编组和解编组功能(您需要在类上实现
readExternal
writeExternal
方法)。这为您提供了绕过反射性能瓶颈的方法

在Java的最新版本中(当然是1.3以后的版本),反射的性能要比以前好得多,所以这已经不是什么问题了。我怀疑您很难从使用现代JVM的
Externalizable
中获得有意义的好处

此外,内置的Java序列化机制不是唯一的,您可以使用第三方替换,例如JBoss序列化,它速度要快得多,并且是默认的替代品

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


总之,
Externalizable
是Java1.1时代的遗物。真的不再需要它了。

在考虑提高性能的选项时,不要忘记自定义序列化。您可以免费让Java做它做得好的事情,或者至少做得足够好,并为它做得不好的事情提供定制支持。这通常比完全外部化支持的代码要少得多。

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


例如,AMF(ActionScript消息格式)远程处理的实现可通过网络传输本机操作脚本对象。

序列化提供了存储和稍后重新创建对象的默认功能。它使用详细格式定义要存储的对象的整个图形,例如,假设您有一个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 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
我们可以观察到,因为我们没有设置密码的值,所以它是空的

同样,也可以通过将密码字段声明为瞬态来实现

private transient String passWord;

希望能有帮助。如果我犯了任何错误,我道歉。谢谢。

可序列化和可外部化

  • 标记接口
    可序列化
    是没有任何方法的标记接口<代码>可外部化接口包含
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(key);
        out.writeUTF(value);
        out.writeObject(emp);
    }
    
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        this.key = in.readUTF();
        this.value = in.readUTF();
        this.emp = (Employee) in.readObject();
    }
    
    
    
    
    
    **In case of Serializable interface**
    
    
            /* 
                 We can comment below two method and use default serialization process as well
                 Sequence of class attributes in read and write methods MUST BE same.
            // below will not work it will not work . 
            // Exception = java.io.StreamCorruptedException: invalid type code: 00\
                  private void writeObject(java.io.ObjectOutput stream) 
                  */
                private void writeObject(java.io.ObjectOutputStream Outstream)
                        throws IOException {
    
                    System.out.println("from writeObject()");
                    /*     We can define custom validation or business rules inside read/write methods.
     This way our validation methods will be automatically 
        called by JVM, immediately after default serialization 
        and deserialization process 
        happens.
                     checkTestInfo();
                    */
    
                    stream.writeUTF(name);
                    stream.writeInt(age);
                    stream.writeObject(salary);
                    stream.writeObject(address);
                }
    
                private void readObject(java.io.ObjectInputStream Instream)
                        throws IOException, ClassNotFoundException {
                    System.out.println("from readObject()");
                    name = (String) stream.readUTF();
                    age = stream.readInt();
                    salary = (BigDecimal) stream.readObject();
                    address = (Address) stream.readObject();
                    // validateTestInfo();
                }