Serializable和ExternalizableJava 之间有什么区别?
Serializable和ExternalizableJava 之间有什么区别?
Answers:
要添加其他答案,请通过实现java.io.Serializable,为类对象提供“自动”序列化功能。无需实现任何其他逻辑,它就可以工作。Java运行时将使用反射来弄清楚如何对您的对象进行封送。
在Java的早期版本中,反射非常慢,因此序列化大型对象图(例如,在客户端-服务器RMI应用程序中)存在一些性能问题。为了处理这种情况,该java.io.Externalizable界面提供,这就好比java.io.Serializable但进行打包和解包的功能自定义编写机制(需要实现readExternal和writeExternal在类上方法)。这为您提供了解决反射性能瓶颈的方法。
在Java的最新版本(当然,从1.3开始)中,反射的性能比以前好得多,因此,这不再是问题。我怀疑您很难从Externalizable现代JVM中获得有意义的收益。
此外,内置的Java序列化机制并不是唯一的机制,您可以获取第三方替代品,例如JBoss序列化,它要快得多,并且是默认替代品。
一个很大的缺点Externalizable是您必须自己维护此逻辑-如果您在类中添加,删除或更改了一个字段,则必须更改您的writeExternal/ readExternal方法以解决该问题。
总而言之,Externalizable是Java 1.1的遗物。真的不再需要它了。
Externalizable帮助。
                    Externalizable适合我,因为我不想输出带有空空格或占位符对象的数组,以及带有可以处理继承的显式接口的输出,这意味着我的同步子对象-class可以轻松地在调用周围添加锁定writeExternal()。是的,Externalizable仍然非常重要,当然对于大型或复杂对象。
                    序列化提供了默认功能来存储和以后重新创建对象。它使用冗长的格式来定义要存储的对象的整个图,例如,假设您有一个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
我们可以观察到,因为我们没有设置passWord的值,所以它为null。
通过将密码字段声明为瞬态也可以实现相同的目的。
private transient String passWord;
希望能帮助到你。如果我有任何错误,我深表歉意。谢谢。
Serializable和之间的主要区别Externalizable
Serializable是没有任何方法的标记界面。Externalizable接口包含两种方法:writeExternal()和readExternal()。Serializable接口的类启动默认的序列化过程。程序员定义的序列化过程将为实现Externalizable接口的类启动。Externalizable界面。您可以支持对象的不同版本。如果实现Externalizable,则序列化super类是您的责任Serializable使用反射来构造对象,不需要arg构造函数。但是Externalizable需要公共的无参数构造函数。请参阅博客通过Hitesh Garg更多的细节。  
对象序列化使用Serializable和Externalizable接口。 Java对象只能序列化。如果一个类或其任何超类实现了java.io.Serializable接口或其子接口java.io.Externalizable。大多数Java类都是可序列化的。
NotSerializableException:packageName.ClassName«要使类对象参与序列化过程,该类必须实现Serializable或Externalizable接口。对象序列化产生一个流,其中包含有关要保存的对象的Java类的信息。对于可序列化的对象,即使存在该类实现的不同(但兼容)版本,也会保留足够的信息来还原那些对象。定义Serializable接口以标识实现可序列化协议的类:
package java.io;
public interface Serializable {};
InvalidClassException«在反序列化过程中,如果本地类为serialVersionUID值与相应的发送者的类不同。然后结果是冲突 
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771对于可外部化的对象,容器仅保存对象类的标识;该类必须保存并恢复其内容。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;
}
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要序列化的类的实例字段。
示例«实现了可序列化
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;
}
示例«实现了可外部化
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();
        }
    }
}
@看到
实际上并未提供Externalizable接口来优化序列化过程的性能!但要提供实现自己的自定义处理的方法,并提供对对象及其超类型的流的格式和内容的完全控制!
这样的示例是实现AMF(ActionScript消息格式)远程处理以通过网络传输本机操作脚本对象的实现。
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
默认序列化有些冗长,并且假定序列化对象的使用范围最广,因此,默认格式(可序列化)会使用有关序列化对象类的信息来注释结果流。
外部化使对象流的生产者可以完全控制精确的类元数据(如果有的话),而不必超出类的最小标识(例如,其名称)。在某些情况下,例如封闭环境中,对象流的生产者及其使用者(从流中对对象进行验证)是匹配的,并且有关该类的其他元数据毫无用处并降低了性能,这显然是合乎需要的。
另外(如Uri所指出的),外部化还提供对与Java类型相对应的流中数据编码的完全控制。对于(人为)示例,您可能希望将布尔值true记录为“ Y”,将false记录为“ N”。外部化允许您执行此操作。
Serializable和Externalizable之间存在太多差异,但是当我们比较自定义Serializable(overrided writeObject()&readObject())和Externalizable之间的差异时,我们发现自定义实现与ObjectOutputStream类紧密绑定,就像在Externalizable情况下,我们自己提供ObjectOutput的实现,该实现可以是ObjectOutputStream类,也可以是诸如org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream之类的其他对象
如果是可外部化的接口
@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();
            }
我添加了示例代码以更好地解释。请检查外部对象的进/出情况。这些不直接绑定到任何实现。
在哪里,出流/入流与类紧密绑定。我们可以扩展ObjectOutputStream / ObjectInputStream,但是使用起来有点困难。