我是一名长期从事C/C++编程的程序员,正在学习Java。我了解到通过返回私有字段的引用来访问器方法会破坏封装的问题,标准的Java解决方案似乎是进行防御性复制 - 调用复制构造函数或clone()来创建字段的副本,并返回对副本的引用。但我不明白为什么没有人关注防御性复制的低效率。在C++中,访问器只需返回指向const的指针,而无需复制即可保护私有成员。为什么Java没有一个指向const的引用?
我是一名长期从事C/C++编程的程序员,正在学习Java。我了解到通过返回私有字段的引用来访问器方法会破坏封装的问题,标准的Java解决方案似乎是进行防御性复制 - 调用复制构造函数或clone()来创建字段的副本,并返回对副本的引用。但我不明白为什么没有人关注防御性复制的低效率。在C++中,访问器只需返回指向const的指针,而无需复制即可保护私有成员。为什么Java没有一个指向const的引用?
注意:我不知道你是否能够找到为什么Java中没有const
的直接答案。(我的猜测是由于Java的动态性质,拥有一个const关键字并没有提供很多编译器优化,因此被认为不值得放入 - 但这只是我的观点。[在C++中,您可以在编译时使用所有最终的具体类型,在Java中则不行。])
至于通常做什么代替,您必须根据数据类型和字段的语义含义做出决策。
一些常见类型(String、Date)是不可变的,并且设计为尽可能少地传递和从getter返回,同时不允许修改。
正如@DavidWallace所指出的那样,有一些方法可以创建一个浅层、不可修改的Map副本,并允许您将其返回给调用者 - 以确保他们不会搞砸它。这是一个实用的解决方案,但它不能在编译时强制执行。
如果我们谈论的是映射:java.util.Map是可变的,根据接口契约,为了实现类似于const的功能,您可以轻松地创建一个不同但简单的接口,只包含一个查找方法:
public interface Lookup<K,V> {
public V get(K);
}
返回该实例。这样可以在编译时保证没有人修改它...因为不存在这样的方法。
实现一个MapLookup,通过包装一个映射而不制作副本来实现上述功能只需要大约5行代码。
如果您确实想确保没有人修改您发送回来的内容,请不要发送可变的内容。 (并且没有理由通过低效的深度复制来完成,如上所述。)
Collections
类中的一整套方法。这些方法的名称类似于unmodifiableList
、unmodifiableMap
等,它们会产生一个对集合的引用,而不是复制它,但也不允许更改集合。 - Dawood ibn Kareem