join() blocks until the thread you call it on terminates. wait() blocks until another thread calls the notify() or notifyAll() method of the object you called wait() on.
In general, join() is used when you've splitten some task in parts to be handled by separate threads concurrently, after which you want to wait until they've all completed. wait() can be used to block until some condition holds true, regardless of whether another thread terminated.
In modern code, you have almost no reason to use these methods. Instead, you should use the high level concurrency classes from the java.util.concurrent packages.
The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.