String s8="abcd"; : Memory will be allocated from constant pool. String s9=s8.toUpperCase(); New object will be created on heap String s11=s8.toUpperCase(); Another New object will be created on heap If you look at the implementation of toUpperCase
public String toUpperCase(Locale locale) { .. return new String(result, 0, len + resultOffset); Hence it creates a new object on heap each time. therefore s9 != s11
Note: If two objects are equal then their hashcodes are equal but vice versa is not true
UPDATE:
String s11=s9.toUpperCase(); s11==s9 // returns true Because there are not chars which can be modified and therefore s11 and s9 both points to the same object. I strongly recommend to you to read the implementation