This is an optimisation called string pooling in which compile-time constant Strings (aka known to be identical at compile time) can be set such that they really are the same object in memory (saving space for one of the most used types of object). Or in the words of the docs;
"All literal strings and string-valued constant expressions are interned."
Note that this only applies to Strings that are defined at compile time, so the following truly would print false.
String a="Hello";
String b=new String("Hello");
System.out.println(a==b); //prints false because a new string was forced
or
String a="Hello";
String b1="He";
String b2="llo";
String b=b1+b2;
System.out.println(a==b); //prints false because b wasn't know to be "Hello" at compile time so could not use string pooling
N.B. It is possible to cause the second snippet to print true by making b1 and b2 final, allowing b1+b2 to be known at compile time. All in all you need to be very careful and treat string==string with considerable respect, in the vast majority of cases you want string.equals(string) in which this behaviour does not exist.