1) It's because String objects are immutable. Once you create a String object and assign it a value, it has the same value forever that cannot be changed. Thus there is always created a new String object when you make any operations with it (for example joining).
In heap there is a special part of it that serves as a pool for String constants. If the compiler encounters a String literal, it first looks into this part of memory whether identical object (String) already exists. If it does, it assigns a reference to this already existing object (String) instead of creating a new one. (This is the reason why Strings are immutable, so no one can change it. Because if several references would point to this String and one of them would change its value, it would create a mess.)
Now let's take a look what is going on in this code snippet and try to find the answer to both of your questions at once.
(1) String a="hello"+"world"; //line 1
(2) String b="hello"; // now b is a literal
(3) String c="world";
(4) String d=b+c;
(5) String e="helloworld";
(6) System.out.println(e==a);
(7) System.out.println(a==d);
(1) First there is created a reference value a that points to type String. Then there is created literal "hello" in this special pool in heap mentioned earlier (1st String object). Then there is created literal "world" in the pool (2nd String object). Then, since Strings are immutable, there is created another literal in this pool- "helloworld" and it is assigned to this reference variable a (3rd String object - this is the answer to your question Nr. 2).
(2) Literals "hello" and "world" created in (1) were created in pool and weren't assigned to any reference value, but they stil exist in this pool. In this line there is reference variable of type String b created and it is assigned to this literal "hello" existing in pool.
(3) same as (2)
(4) Created reference value of type String d. Although there already IS a String literal in this special heap part (pool) with value "helloworld", a new String object with value "helloworld" is created in heap - that means in non-pool part of heap. Therefore you have two different objects of type String with value "helloworld" (One in a pool and the other in a non-pool part of heap). If you now compare with == operator reference values a and d, both of them point to different objects (with same value though, so method equals would return true).
(5) Created reference value e of type String. In pool part of heap there already is a String "helloworld" (we created it in (1) and pointed it to reference variable a) so the reference variable e is assigned to this object. And points to same place as a. Therefore if you compare references a == e you get true. The same would be for method equals
(6) and (7) were explained in previous points
TLDR:
1) because it is not the same object
2) 3