解释 Java 的序列化机制
Java 序列化(Serialization)是将一个 Java 对象的状态转换成字节流,从而支持持久化存储或网络传输;反序列化将该字节流恢复成原始对象。
1. 如何启用序列化
● 类需实现 java.io.Serializable(标记接口),使其可被 ObjectOutputStream 写出,ObjectInputStream 读入。
● 非静态、非瞬态(transient)字段默认参与序列化。
● transient 修饰的字段不会被序列化,反序列化后为默认值(如 int = 0, String = null)。
2. 控制版本兼容性
● static final long serialVersionUID 用以版本匹配,手工声明可避免自动生成导致的兼容性问题;若版本不一致出现 InvalidClassException。
3. 自定义序列化行为
● 实现 writeObject(ObjectOutputStream) 与 readObject(ObjectInputStream):在调用 defaultWriteObject() 后,可插入数据检查或额外逻辑。
● readResolve():在反序列化最后替换或校正返回对象(如保证单例),比直接使用 readObject() 更清晰。
4. 安全与性能优化
● 安全:禁止类被反序列化,重写 readObject() 抛异常;或用 readResolve() 控制实例;推荐采用序列化代理模式(序列化期间替换为简单 DTO,对其反序列化时再恢复原始对象) 。
● 性能:使用 Externalizable 自定义读写逻辑,减少无用字段;或切换到更高效的序列化库,如 Protobuf、Kryo 。
Java 中设计模式按应用目的如何分类?
Java 的设计模式根据目的主要分为三类:创建型、结构型和行为型,每类都有典型应用场景和代表模式。
1. 创建型(Creational) 关注“如何创建对象”,提升灵活性与可复用性。
● 单例(Singleton):保证类只有一个实例,常用于日志管理、配置中心。
● 建造者(Builder):适合构建复杂对象,比如带多可选参数的 HTTP 请求或配置对象。
场景示例:在构建一个 User 对象时,如果有多个可选字段,使用 Builder 可避免构造函数多参数问题。
2. 结构型(Structural) 关注对象之间如何组合、连接,形成稳定可扩展的架构。
● 适配器(Adapter):将一个类的接口转换成客户期望的另一种接口,常用于第三方接口接入,例如将旧系统的 DAO 接口适配为新的服务调用接口。
● 装饰器(Decorator):在运行时给对象动态添加功能,比如 java.io 的流包装机制(如 BufferedInputStream 包裹 FileInputStream)。
3. 行为型(Behavioral) 关注对象之间的交互和职责分配,模式关注通信方式。
● 策略(Strategy):定义一系列算法,将它们封装成策略类,比如排序模块可以把不同排序逻辑抽象为策略,客户端可动态选择。
● 观察者(Observer):定义一对多依赖,当一个对象状态改变时,所有相关对象自动收到通知,例如事件监听机制、MVC 中的 View 与 Model 通信。
两个对象的 hashCode() 相同,是否它们的 equals() 一定返回 true?
在 Java 中,hashCode() 和 equals() 的关系遵循严格但单向的约定:若两个对象通过 equals() 比较相等,那么它们的 hashCode() 必须相同;但反过来,hashCode() 相同并不保证它们通过 equals() 相等,这是因为哈希碰撞是可能的 —— 不同对象可能得到相同的哈希码 。