There are quite a lot of answers here which exlain that, but let me give you another one. 
A string is interned into the String literal pool only in two situations: when a class is loaded and the String was a literal or compile time constant. Otherwise only when you call .intern() on a String. Then a copy of this string is listed in the pool and returned. All other string creations will not be interned. String concatenation (+) is producing new instances as long as it is not a compile time constant expression*.
First of all: never ever use it. If you do not understand it you should not use it. Use .equals(). Interning strings for the sake of comparison might be slower than you think and unnecessarily filling the hashtable. Especially for strings with highly different content.
- s3 is a string literal from the constant pool and therefore interned. s4 is a expression not producing an interned constant.
- when you intern s4 it has the same content as s3 and is therefore the same instance.
- same as s4, expression not a constant
- if you intern s1+s2 you get the instance of s3, but s4 is still not s3
- if you intern s4 it is the same instance as s3
Some more questions:
System.out.println(s3 == s3.intern());       // is true
System.out.println(s4 == s4.intern());       // is false
System.out.println(s1 == "abc");             // is true
System.out.println(s1 == new String("abc")); // is false
* Compile time constants can be expressions with literals on both sides of the concatenation (like "a" + "bc") but also final String variables initialized from constants or literals:
    final String a = "a";
    final String b = "b";
    final String ab = a + b;
    final String ab2 = "a" + b;
    final String ab3 = "a" + new String("b");
    System.out.println("ab == ab2 should be true:  " + (ab == ab2));
    System.out.println("a+b == ab should be true:  " + (a+b == ab));
    System.out.println("ab == ab3 should be false: " + (ab == ab3));