如何修复Java Date类使其实例创建后日期不可修改?
修复Date类不可变性的两种方案(最简&最优)
这个问题其实是典型的封装破坏——你把内部可变数组的直接引用返回给了外部,外部代码自然能通过这个引用修改你的内部状态,完全违背了Date实例不可修改的设计初衷。下面给你两种修复方案,按需选择:
方案1:最简快速修复——返回数组副本
只需要修改getDate()方法,返回内部数组的克隆副本,而不是原引用。这样外部拿到的是独立的新数组,修改它不会影响Date实例内部的ymd数组。
修改后的Date类代码:
public class Date { private int[] ymd = new int[3]; public Date(int year, int month, int day) { ymd[0] = year; ymd[1] = month; ymd[2] = day; } // 核心修改:返回数组的克隆副本 public int[] getDate() { return ymd.clone(); // 也可以用Arrays.copyOf(ymd, ymd.length)效果一致 } public void printDate() { System.out.println(ymd[0] + "-" + ymd[1] + "-" + ymd[2]); } }
运行Problem2代码后,两次输出都会是2019-6-15,因为外部修改的是副本,和Date内部的数组完全无关。
方案2:最优长期方案——拆分成员变量(更符合封装语义)
其实用数组存年、月、日本身就不太贴合Date类的语义,把成员变量拆成单独的year、month、day三个int字段,不仅能彻底避免数组引用泄露的问题,代码可读性和封装性也更好。同时可以把字段设为final,从根源上强化不可变性。
修改后的Date类代码:
public class Date { private final int year; private final int month; private final int day; public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } // 提供单独的语义化getter public int getYear() { return year; } public int getMonth() { return month; } public int getDay() { return day; } // 如果需要保留getDate方法,依然返回新数组 public int[] getDate() { return new int[]{year, month, day}; } public void printDate() { System.out.println(year + "-" + month + "-" + day); } }
这种方案下,Date实例的字段一旦初始化就无法修改,完全保证了不可变性,同时代码更清晰易维护,是长期来看的最优选择。
方案对比
- 方案1是临时快速修复,只改一行代码就能解决当前问题;
- 方案2是合理的架构优化,符合面向对象封装原则,彻底杜绝类似问题,适合作为长期的代码设计。
内容的提问来源于stack exchange,提问作者Calle654
相关产品推荐
相关产品推荐

