问题
I'm a longtime C/C++ programmer who's learning Java. I've read about the problem of breaking encapsulation by having an accessor method that returns a reference to a private field. The standard Java solution seems to be defensive copying - calling the copy constructor or clone() to create a copy of the field and returning a reference to the copy. I don't understand why no one seems concerned about the inefficiency of making a defensive copy. In C++, the accessor would just return a pointer to const, protecting the private member without copying. Why doesn't Java have a reference to const?
回答1:
Why doesn't Java have a reference to const?
Questions can only be properly answered by the language designer, but I think that the problem was that they couldn't figure out how to make it work as part of the language design. My recollection (from some "Java design rationale" document that I came across one time) was that Gosling et al originally wanted to support const
...
In fact, though both C and C++ both support const
as a way of expressing a mutability constraint, they both also have loopholes that allow some code to "break" the constraint. (See the Wikipedia article on const-correctness.) It could be that it was the difficulty of coming up with a design for Java that didn't have (or need) such loopholes that caused Gosling et al to abandon that idea.
The flip-side is that the need for defensive copying in Java is not as great as you might imagine, and that the cost of doing it is not as great as you might imagine. And when the cost of the defensive copy is significant, there are other options in Java ... like creating "unmodifiable" wrapper objects, or interfaces that only support "read" operations.
回答2:
NOTE: I don't know that you're going to find a direct answer to the question of why there is no const
in Java. (My guess is because due to the dynamic nature of Java, having a const keyword did not provide as many compiler optimizations and thus was deemed not worth putting in - but that's just my opinion. [In C++ you have all of the final concrete types available to you at compile time, in Java, you don't.])
As for what is generally done instead, you have to make a decision based on the data types and what your fields semantically mean.
Some common types (String, Date) are immutable and are designed to be passed around and returned from getters with as little overhead as possible while not allowing modification.
As @DavidWallace points out, there are methods which create a shallow, unmodifiable copy of a Map and allow you to return that to caller - to guarantee they won't mess with it. This is a practical solution, however it does not enforce it at compile time.
If we're talking about maps: A java.util.Map is, per the interface contract, mutable. To achieve something close to const, you can easily create a different but simple interface with only a lookup method:
public interface Lookup<K,V> {
public V get(K);
}
And return an instance of that. Thus guaranteeing nobody will modify it... at compile time... because no such method exists.
And implementing a MapLookup that implements the above by wrapping a map without making a copy is like 5 lines of code.
If you want to make really sure that nobody modifies what you send back, don't send back something that is mutable. (And there's no reason it has to be done via an inefficient deep copy, as explained above.)
来源:https://stackoverflow.com/questions/19192762/inefficiency-of-defensive-copy-in-java