引起这个疑问,还是从Hibernate使用查询缓存说起;对象实例除了存在于内存,二级缓存还会将对象写进硬盘在需要的时候再读取出来使用,此时就必须提到一个概念:序列化。
程序在运行时实例化出对象,这些对象存在于内存中,随着程序运行停止而消失,但如果我们想把某些对象(一般都是各不相同的属性)保存下来或者传输给其他进程,在程序终止运行后这些对象仍然存在,可以在程序再次运行时读取这些对象的信息,或者在其他程序中利用这些保存下来的对象信息恢复成实例对象。这种情况下就要用到对象的序列化和反序列化。
其实很早就知道的,在Java中常见的几个类,如:Interger/String等,都实现了java.io.Serializable接口。这个序列化接口没有任何方法和域,仅用于标识序列化语意;实现 Serializable 接口的类是可序列化的,没有实现此接口的类将不能被序列化和反序列化。序列化类的所有子类本身都是可序列化的,不再需要显式实现 Serializable 接口。只有经过序列化,才能兼容对象在磁盘文本以及在网络中的传输,以及恢复对象的时候反序列化等操作。
问题一:为何要实现序列化?
答:序列化就是对实例对象的状态(State 对象属性而不包括对象方法)进行通用编码(如格式化的字节码)并保存,以保证对象的完整性和可传递性。
简而言之:序列化,就是为了在不同时间或不同平台的JVM之间共享实例对象
// 经常使用如下: public static void main(String[] args) throws Exception { File file = new File("user.ser"); ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file)); User user = new User("zhang", 18, Gender.MALE); oout.writeObject(user); oout.close(); ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file)); Object newUser = oin.readObject(); oin.close(); System.out.println(newUser); }
如没有 实现Serializable接口,在序列化时,使用ObjectOutputStream的write(object)方法将对象保存时将会出现异常。其实 java.io.Serializable 只是一个没有属性和方法的空接口,但是问题来了。。。
问题二:为何一定要实现 Serializable 才能进行序列化呢?
使用 ObjectOutputStream 来持久化对象, 对于此处抛出的异常,查看该类中实现如下:
private void writeObject0(Object obj, boolean unshared) throws IOException { // ... // 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) { writeOrdinaryObject(obj, desc, unshared); } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } } // ... }从此可知,如果被写对象类型是String、数组、Enum、Serializable,就可以进行序列化,否则将抛出NotSerializableException。
最后提点注意:
1、在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,如此引用传递序列化。如果一个对象包含的成员变量是容器类等并深层引用,那么序列化过程开销也较大。
2、当字段被声明为 transient 后,默认序列化机制就会忽略该字段。(还有方法就是自定义writeObject方法,见下代码示例)
3、在单例类中添加一个readResolve()方法(直接返回单例对象),以保证在序列化过程仍保持单例特性。
此外补充一下,
在路径下jdk中还有另外一种形式的对象持久化,即:外部化(Externalization)。
public interface Externalizable extends java.io.Serializable { void writeExternal(ObjectOutput out) throws IOException; void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; }
外部化和序列化是实现同一目标的两种不同方法。
通过 Serializable 接口对对象序列化的支持是jdk内支持的 API ,但是java.io.Externalizable的所有实现者必须提供读入和写出的具体实现,怎么实现完全由你自定义。序列化(Serializable )会自动存储所有必要的信息(如属性以及属性类型等),用以反序列化成原来一样的实例,而外部化(Externalizable)则只保存被存储实例中你需要的信息。
示例代码如下:
public class User implements Externalizable { private String name; transient private Integer age; // 屏蔽字段 private Gender gender; public User() { System.out.println("none constructor"); } public User(String name, Integer age, Gender gender) { System.out.println("arg constructor"); this.name = name; this.age = age; this.gender = gender; } // 实现读写 private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(age); // 屏蔽gender } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); age = in.readInt(); } // 具体重写 @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(age); // 屏蔽gender } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); age = in.readInt(); } }注意,用Externalizable进行序列化,当读取对象时,会调用被序列化类的无参构造器创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。实现Externalizable接口的类必须要提供一个无参的构造器,且访问权限为 public。
相关推荐
首先,要实现序列化,一个Java类必须实现`Serializable`接口。这是一个标记接口,没有定义任何方法,只是告诉Java虚拟机(JVM)这个类的对象是可以序列化的。例如: ```java public class MyEntity implements ...
此外,实体类还需要实现序列化接口(Serializable),以便于在网络传输或持久化时使用。在生成的实体类中,可能会包含一些特殊的注解,如`@Entity`(表示这是一个实体类)、`@Table`(指定对应的数据库表名)、`@Id`...
5. **注释和序列化支持**:为了提高代码可读性和与其他框架的兼容性,生成的实体类可能还包括JPA的注解(如@Entity、@Id等)和Java Serializable接口。 6. **文件输出**:最后,工具将生成的实体类代码保存到指定的...
4. **序列化接口**:为了支持对象的序列化和反序列化,实体类通常会实现`java.io.Serializable`接口。 5. **注解**:在ORM框架中,实体类通常需要使用注解来指定与数据库表的关系。例如,Hibernate使用的`@Entity`...
- **序列化和反序列化**:如果实体类实现了`Serializable`接口,可以利用`ObjectOutputStream`和`ObjectInputStream`进行序列化和反序列化实现深拷贝。这种方式的优点是简单,但缺点是效率较低,且所有属性都需要...
- **序列化**:如果你希望实体类可以被序列化,记得添加`Serializable`接口。 - **注解配置**:ORM框架如Hibernate或MyBatis可能需要额外的注解来配置实体类,如`@Table`、`@Column`等。 5. **辅助工具和框架** ...
这可能包括字段的命名规则、是否生成equals()和hashCode()方法、是否添加序列化注解`@Serializable`,甚至是否启用Lombok库来简化getter和setter的生成。模板配置的灵活性确保了代码风格的一致性,同时也满足了不同...
- 在生成自跟踪实体模板时,需要确保实体类实现了必要的接口(例如`IObjectWithChangeTracker`),以便正确地管理这些状态。 2. **变化跟踪接口** - **IObjectWithChangeTracker**:这个接口定义了用于管理实体...
在压缩包中的`xmlEntity`文件可能是实现这些转换的源代码,包括实体类定义和转换方法的具体实现。分析并理解这些代码可以帮助我们更深入地了解作者是如何处理XML和实体对象的转换的。 总的来说,XML与实体对象的...
在微服务架构中,实体类需要实现Serializable接口,以便在不同服务之间传递数据。但是,如果项目中不需要将实体对象传输或存储在不同的系统之间,那么可能不需要让每个实体类都实现Serializable。 在分布式系统中,...
5. **序列化支持**:为了在不同组件间传递或者持久化对象,Entity类往往需要实现`Serializable`接口。 6. **JPA规范**:如果使用了JPA,那么Entity类需要遵循其规定,如避免使用final、static和transient关键字,...
因此,实体类需要实现Serializable接口,确保能被正确序列化和反序列化。 五、总结 "hello-dubbo-entity"项目揭示了在Dubbo环境中如何有效地利用实体类进行数据交换。理解实体类在Dubbo框架下的工作原理和使用方式...
Serializable 接口是用于标识一个类可以被序列化的。在复合主键类中,我们需要实现 Serializable 接口,以便 Hibernate 框架可以正确地序列化和反序列化复合主键。 复合主键在 Hibernate 中的使用 在 Hibernate 中...
如果某个类实现了序列化接口(通常是`Serializable`),那么它的子类也可以被序列化。值得注意的是,`static`和`transient`修饰的成员变量不会被序列化,因为它们分别表示类的状态和对象的临时数据,不是对象持久化...
默认情况下,由于生成的STE类没有实现`[Serializable]`接口或`ISerializable`接口,所以无法直接通过ViewState进行序列化和反序列化。 为了解决这个问题,我们需要对STE的T4模板进行修改,以使它们支持序列化。T4是...
2. **Serializable接口**: 在`Cash`、`ShangPin`和`User`类中都实现了Serializable接口,这是因为在Java中,当对象需要在网络间传输或者持久化存储时,必须实现Serializable接口。序列化允许将对象的状态转换为字节...
在Java中,可以通过实现Serializable接口来实现对象的序列化,将对象转换为字节流并写入文件,然后在需要时反序列化读取。然而,对象间的引用关系处理起来较为复杂,需要确保整个对象引用闭包(Persistence closure...
1. Entity类:对应数据库表的字段,包含getter/setter方法,实现了Serializable接口,便于序列化。 2. Mapper接口:定义了数据库操作的CRUD方法。 3. Mapper XML文件:包含了SQL语句的具体实现,与Mapper接口相对应...