Java中防御性副本的低效

Dav*_*eal 5 java performance defensive-programming defensive-copy

我是一名长期 C/C++ 程序员,正在学习 Java。我读过有关通过使用返回对私有字段的引用的访问器方法来破坏封装的问题。标准的Java解决方案似乎是防御性复制——调用复制构造函数或clone()来创建字段的副本并返回对该副本的引用。我不明白为什么没有人担心制作防御性副本的低效率。在 C++ 中,访问器只会返回一个指向 const 的指针,从而保护私有成员而不进行复制。为什么Java没有const引用?

Bra*_*ody 0

注意:我不知道您是否会找到“为什么 Java 中没有”这个问题的直接答案const。(我的猜测是因为 Java 的动态特性,拥有 const 关键字并没有提供尽可能多的编译器优化,因此被认为不值得投入 - 但这只是我的观点。[在 C++ 中,你拥有所有最终的具体类型在编译时可用,但在 Java 中则不能。])

至于通常做什么,您必须根据数据类型和字段的语义含义做出决定。

一些常见类型(String、Date)是不可变的,并且被设计为以尽可能小的开销从 getters 传递和返回,同时不允许修改。

正如 @DavidWallace 指出的,有些方法可以创建 Map 的浅层、不可修改的副本,并允许您将其返回给调用者 - 以保证他们不会弄乱它。这是一个实用的解决方案,但它不会在编译时强制执行。

如果我们谈论映射:根据接口契约,java.util.Map 是可变的。要实现接近 const 的功能,您可以轻松创建一个不同但简单的接口,仅使用查找方法:

public interface Lookup<K,V> {
    public V get(K);
}
Run Code Online (Sandbox Code Playgroud)

并返回一个实例。因此保证没有人会在编译时修改它......因为不存在这样的方法。

而实现一个通过包装地图而不进行复制来实现上述功能的MapLookup就像5行代码。

如果您想真正确保没有人修改您发回的内容,请不要发回可变的内容。(正如上面所解释的,没有理由必须通过低效的深度复制来完成。)