(to clarify Majestic's post:
== works exactly as the language definition says it should, including for Strings. It tests for two references being equal, ie referring to exacty the same object. However, it doesn't do what beginners sometimes think it does, ie test for two Strings containing the same sequence of characters - that needs the equals method)
Because Strings are immutable the compiler is able to optimise String literals by sharing them.
eg1,2: It creates a "hello" string for the first statement, then re-uses the same string for the second. The == test (tests for being the same object) is true.
eg3,4: Using new String explicitly overrides the compiler's optimisation and forces it to create new String object. Now there are two different String objects, so == is false. (But x.equals(y) is true becuase they both contain the same sequence of characters)