I had to do this once, and ended up using the UUID inside the SMBios.
In my case, I used C in a unix environment, not Java, but you might be interested in reading the SMBios specification, and take a shot at reading the UUID, which should be a little better than reading MAC's, hard disks serial numbers, etc, because the user might replace these more often than the bios.
EDIT: Updated to add what we've discussed in the comments (just to have everything together in the same place).
On virtual machines (VMWare, that is), the UUID is generated from the UUID of the physical machine and the path to where the vm "lives" (see: http://www.vmware.com/support/ws55/doc/ws_move_uuid_format.html)
For Java, I know there's javax.realtime.RawMemoryAccess, that let's you read and write memory. I've never actually tried it, but seems to be the right way to do it from Java (if anyone's got any experience on this please comment!)
Otherwise, there's a not-that-portable solution: a JNI, and that means C++. As I stated before, my only experience was on unix systems, and in my particular case I found the source for dmidecode, quite helpful. For windows, you could try this SO question, which might be helpful.
Yes, I know it might look like a lot to research on at first :) But I guess that reading the specification and (if needed) looking at the source of dmidecode, you should be able to do it, and will (in my experience) yield better results "in the field" than hashing serial numbers from disks or network cards.