What is the Java equivalent of C++'s const member function?
In C++, I can define an accessor member function that returns the value of (or reference to) a private data member, such that the caller cannot modify that private data member in any way.
Is there a way to do this in Java?
If so, how?
I know about the final
keyword but AFAIK, when applied to a method it:
- Prevents overr开发者_Go百科iding/polymorphing that method in a subclass.
Makes that method inline-able.(see comment by @Joachim Sauer below)
But it doesn't restrict the method from returning a reference to a data member so that it can't modified by the caller.
Have I overlooked something obvious?
There's no equivalent to the C const
"type modifier" in Java (sadly).
The closest you can get is to return an immutable object or an immutable wrapper around a mutable object.
Immutability is not a language feature of Java, however, so you'll have to rely on Libraries.
Examples of immutable objects are:
- the primitive wrappers
Integer
,Character
, .. String
File
URL
Commonly used immutable wrapper (i.e. wrappers around mutable types that prevent mutation) are those returned by the Collecton.unmodifiable*()
methods.
This does not exist in java. final
and const
have different semantics, except when applied to a variable of a primitive type. The java solution typically involves creating immutable classes - where objects are initialized in construction and provide no accessors allowing change. Example of such classes would be e.g. String
or Integer
.
You either return an immutable object, or return a copy of the private instance variable. This way, the object's internal state is "protected" from modification, i.e.:
private MyMutableObject mutable = ...
public MyMutableObject getMutableObject() {
return new MyMutableObject(this.mutable);
}
`
You haven't overlooked anything. There is no way in pure Java to do so. There might be libraries which provide some subset of this using annotations, but I don't know any offhand.
The way you pass back a reference to immutable data is to make the class you pass back immutable, plain and simple. There are a couple of library functions to help you produce an immutable view of some data in some very limited but common cases. Here's one example:
private List<String> internalData;
public List<String> getSomeList() {
return Collections.unmodifiableList(internalData);
}
You could return a copy of the member, thus changes will not be reflected in the object the private reference points to. With primitives, of course, this problem doesn't exist.
Be mindful of memory usage, however! This might not be the right solution for all situations. In that case, an immutable object as suggested in another answer might be the way to go.
I don't think there is a way to that in Java for non primitive objects (you're always passing around references to such objects). The closest you could do would be to return a copy of the object (using clone or something like that) ; but that would not be very idiomatic Java.
I you want to give access only to the 'visible' part of a member object, what you could do is create an interface with the visible part, and return this interface. For example :
public interface Bar {
public int getBing();
}
public class BarImpl implements Bar {
private int bing;
public int getBing() {
return bing;
}
public void setBing(int bing) {
this.bing = bing;
}
}
public class Foo {
private BarImpl bar;
public Bar getNonModifiableBar() {
return bar; // Caller won't be able to change the bing value, only read it.
}
}
One way to avoid this issue is to no expose the data structure (another is returning a copy, or an immutable wrapper)
e.g. instead of
public List<String> getSomeList();
have
public String getSomeElement(int index);
When you do something like this:
Object2 obj2 = obj1.getObj2();
obj2 = new Object2();
The original private member (obj1.obj2) remains as it were before (just to be sure that you grasped that concept). You can just omit the setter to obj2 so that the inner field cannot de changed.
If you want Object2 fields to be immutable you will need to apply the same pattern (private fields, no setters).
This answer your question?
It's up to the returned object to prevent modification. Java doesn't provide declarative/compile-time checking of unmodifiable objects except to the extent that the type lacks mutators.
There is some support in the JDK: methods like Collection.unmodifiableCollection will create an object that will throw runtime exceptions if the client calls collection mutator methods.
If you're truly motivated, you can get compile-time checks by defining read-only interfaces (or classes) that only expose/implement accessor methods on your own. Keep in mind that merely declaring that a method returns a read-only interface will not prevent runtime modification if the client uses introspection and the object provides mutators (that don't throw UnsupportedOperationException).
精彩评论