Effective Java - 必要时进行保护性拷贝
2022-07-23 本文已影响0人
DZQANN
第50条 必要时进行保护性拷贝
-
Example:
public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { if (start.compareTo(end) > 0) throw new IllegalArgumentException( start + " after " + end); this.start = start; this.end = end; } public Date start() { return start; } public Date end() { return end; } }
这里有一个比较严重的问题,是虽然把
start
和end
变成了final
,但是Date
本身还是一个可变的,如果外边塞了start
之后又改变了Date
的值,就会导致Period
的计算结果错误。可以修改为:
public Period(Date start, Date end) { if (start.compareTo(end) > 0) throw new IllegalArgumentException( start + " after " + end); this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); }
-
Date
已经过时了,不应该在新代码中依然使用Date
-
对于构造器里面的每个可变参数进行保护性拷贝是必要的
-
保护性拷贝实在检查参数的有效性之前进行的,并且有效性检查针对的是拷贝之后的对象。这么做的目的是避免多线程对于变量的修改
思考
- 这一节说的问题确实是存在的,不过在项目里不需要太注意。类里面的成员应该尽可能保证只读
- 如果编写了大部分人都会调用的底层接口,则需要考虑对入参进行复制。特别是类成员的
get
方法,在这种情况下应该尽量返回一个副本。底层接口不会知道使用比人是怎么用它的,只能自己尽量保证安全