Strings literals are kept in the static string pool in Java, so that whenever you use a string literal that is already contained in the pool it is being reused instead of wasting the memory creating a new one. That is what's happening in your program - "abcd" is already contained in the string pool, so s2 assigned the same address as s.
You can force the creation of strings like this - String s2 = new String("abcd");, now the "==" won't work.
This post has been edited by Neumann: 10 September 2009 - 08:32 AM
The reason why you don't use == is not because it comes up false when they are the same, its because it can be inconsistent with caching and efficiency adjustments you can't know whether or not its going to come up true or false at any one time.