So it’s a known fact that Java passes references by value. That means that if I pass an Object of some kind into a method, I can change the values in the object, but not the object reference itself.
Likewise, if I pass an int into a method, I can change the value of that int within the method block, but that doesn’t affect the scope of the int outside that block.
This means that doing stuff like:
void swap(int a, int b) { // relax, folks, this is simpler to understand and closer to my main point int c=a; a=b; b=c; }
… won’t work.
After you call that method, with something like this:
int a=1, b=2; swap(a, b); // a==2 now, and b==1, right? Errr... no.
… a will remain 1, b will remain 2. Inside the method, the values will change (because the references on the stack will have changed) but outside, nothing.
However… Reinier Zwitserloot (of Lombok and http://tipit.to/, which I’m going to start using because I’m broke and I want a Mac, darn it!) pointed something out today about which I honestly had no idea.
So, being a curious sort who likes to play with things, I started batting about … the AtomicInteger.
With this, you can pass around a reference that contains a reference to an immutable object. That sounds dull and everything, but it’s actually a formal Java-approved way to do something most of us have done when we needed stuff like this: it’s a container object, and we can use that container object to change out references cleanly.
It’s actually rather neat, even if it looks uglier in code. Here’s a swap(), that operates on AtomicIntegers instead of Integers, and works:
void swap(AtomicInteger i3, AtomicInteger i4) { Integer v = i3.get(); i3.set(i4.get()); i4.set(v); }
There’s still some lameness here, though: the use of AtomicInteger as a concrete type. In and of itself, it’s fine, but… it means if we have other types, we have to overload that method name.
All together now: “Eww. There has to be a better way.” And there is: generics. We can apply them to the swap() method, and use AtomicReference
<T> void doSwap(AtomicReference<T> i3, AtomicReference<T> i4) { T middle=i3.get(); i3.set(i4.get()); i4.set(middle); }
Calling it looks like this:
AtomicReferencei3 = new AtomicReference (1); AtomicReference i4 = new AtomicReference (2); System.out.printf("i3=%d, i4=%d%n", i3.get(), i4.get()); doSwap(i3, i4); System.out.printf("i3=%d, i4=%d%n", i3.get(), i4.get());
It’s a little verbose, but it works. Java programmers are used to working around it somewhat (hey, it’s been fifteen years of pass by value!) but it’s still cool to see this put in the language API – especially since they’re threadsafe.
However… note that these methods are not threadsafe! In order to be threadsafe, they need to use a latch, to make sure the references don’t change between assignments. That’s another entry altogether, though, and is actually a thorny subject.
Refer to Java Concurrency in Practice for more detail, or watch this space; I’ll eventually get to it.
Author’s Note: A rather brave repost, and the first of this series I’d considered not reposting.