... Is it because local variables are allocated on the stack, and so my new is blown away when I exit the method?
No. It is because of the argument passing semantics of Java.
Java arguments are passed "by value", but in the case of an object or array type, the value you are passing is the object/array reference. When you create and assign a new set object to mySet
, you are simply setting the local variable / parameter. Since Java uses pass by value, this has no effect on the foo
variable in the main
method.
When you enter the test
method, you have two copies of the reference to the HashSet
instance created in the main
method; one in foo
and one in mySet
. Your code then replaces the reference in mySet
with a reference to a newly created HashSet
, but this new reference doesn't get passed back to the caller. (You could change your code to pass it back ... for example as the result of the test
method. But you have to do this explicitly.)
OK - however -- if I were to do add or some other operation within my method call, that allocation would be preserved. Why is that?
That is because when you call an instance method using the reference in foo
or mySet
, that method is executed on the object (HashSet
) that the reference refers to. Assuming that the two references point to the same object, your "allocation will be preserved". Or more precisely, you can observe the effects of operations on one reference to an object via operations on other references to the same object.
Just remember that Java method calls copy references to object, not the objects themselves.
By the way you won't be able to add elements to a set returned by Collections.emptySet()
. That set object is immutable. Calling (for example) add
on it will throw an exception.