gaijinco said:
For example in a constructor, obviously you will never want that a
parameter in a constructor to lose its value, at least before making
the correponding assigment with the appropiate atribute.
The parameter cannot "lose its value".
A parameter in a constructor (or method, static or otherwise) is really
a local variable in disguise, one that gets preassigned with the result
of evaluating some expression where the method or constructor got called.
What happens if I execute
Foobar f = new Foobar(someList)
private List myList;
public Foobar (List theList) {
myList = theList;
}
is more or less as follows.
A reference "f" is allocated on the stack.
The expression "someList" is evaluated, presumably to a List reference
(under the hood this is most probably a machine pointer).
Memory for a new Foobar is allocated (here is where any OOME is thrown),
including for a reference "myList".
A reference "theList" is allocated on the stack.
The pointer to the list referenced by "someList" is copied to "theList".
The code being run jumps into the Foobar constructor's code.
The pointer at "theList" is copied to "myList".
At some time during all of this, the "f" reference is made to point to
the new Foobar object being constructed.
This is what happens conceptually; there may well be optimizations in
practise, especially with JIT compiling.
In any event, if "someList" is reassigned before the constructor is
called, the newer value is what gets copied to "theList"; otherwise the
older value is copied. (With concurrency, a race condition may make it a
toss-up which version gets copied.)
But "theList" gets one version or the other, and this version is copied
to "myList". If "someList" is changed to point to another List (or to
"null") after it was copied to "theList", "theList" still points to the
earlier List, and "myList" still ends up pointing to that List.
Maybe it's easier if an integer is used. A machine pointer and an
integer are probably the same thing at the bottom level, modulo the
hardware you use, anyway, but some things should be clearer.
So "someInteger" is equal to, say, 5. When the constructor is called,
"theInteger" gets set equal to 5. If "someInteger" is changed to 6 by
some concurrent code, "theInteger" remains equal to 5, because it's a
different integer; it's a copy. Eventually "myInteger" ends up being 5
(not 6).
The tricky case is when the object is mutable. So "someList" points to a
list, "theList" gets pointed to the same list, and someone adds
something to the list, then "myList" gets pointed to the list. Since
there's only the one list, the change is visible everywhere, but it
wouldn't have mattered. If the change happened before "theList" was
assigned, "myList" still ends up pointing to this list, and still it has
the extra item. If "myList" points to the list before the change is made
to the list, "myList" stays pointing to the same list, but someone
iterating over the list a couple of times with "for (Foo x : myList)"
may see a new item the second time they do so. This isn't peculiar to
constructors, and it wouldn't be prevented by making "theList" final, or
even by making "myList" final. This doesn't stop the list being
modified; it only stops the named reference being pointed at some other
list later, or becoming null.
Even using "Collections.unmodifiableList" somewhere along the way won't
stop someone changing the list that has a reference to the original list
object and not just the wrapper returned by the aforementioned method,
or make the list change invisible to "myList" users.
To make the list never get modified of course it can be wrapped in
"unmodifiableList" as soon as it's built and populated appropriately,
and all direct references to the original, mutable list discarded.
To make the Foobar constructor not see any modifications means passing
it a copy of the list: "Foobar f = new Foobar(new ArrayList(someList));"
To make the Foobar object unable to ever see any modifications the
constructor itself can copy the list: "myList = new ArrayList(theList);"
Even then the Foobar might have methods "return myList;" and then see
changes made to the list; "return Collections.unmodifiableList(myList);"
prevents that, and a single unmodifiable view can be constructed and
stored in an ivar to return instead of making a new one each time of
course. Either way the Foobar has a private copy of the list and doesn't
let anyone else ever get hold of a reference to it that can be used to
change it.
And even then, if the list contains objects that are themselves
modifiable, such as more lists, or sets or maps or whatever, one of
these might be altered and the change visible through the Foobar
instance's "myList" ivar.
Needless to say, it is often best to use unmodifiable object types,
including Collections.unmodifiableFoo, liberally, and encapsulate all
mutable state. Making ivars "final" helps make and enforce unmodifiable
object types.
Making constructor (or other) parameters "final" doesn't do anything of
the sort.