Below are important Question & Answers taken from the Q&A discussions in this section.
Q1. With regards to StringPool lecture, it was said string literals are known at compile time where as string variables are known at runtime; what is the difference between knowing at runtime and compile time?
Answer: Let's consider the same example statements from lecture, but let's consider only the following ones that will help us here. In the below code, in the first println statement, compiler knows both "hel" & "lo!" are constants (they cannot change) and so concatenates them at compile itself (and stores it in .class file as "hello!" in a location called constant pool and at runtime it goes on string pool). But, with second statement, compiler will not do concatenation as s5 is variable. Had s5 been declared as final String s5 = "lo!", then no problem and s5 is considered constant and so compiler will replace s5 with "lo!" and will do concatenation. But, without final, the concatenation will happen only at run-time and anything concatenated at run-time MUST go outside string pool (unless they are forced to go into String pool by invoking intern()). Essentially, anything string-related (including concatenation) known at compile-time will go on string pool while the rest string-related things (including concatenation) known at runtime will go outside string pool (unless of course intern() is used).
You may ask why can't compiler copy "lo!" in below case? Imagine there is some statement in between which is like 's5 = getVal();', i.e., s5 is getting re-assigned by whatever getVal() returns and it is impossible for compiler to figure that out. So, that's the reason compiler will not do concatenation in the second println. Below I am also including a relevant reference where the first answer by user 'assylias' explains the same thing.
String s1 = "hello!";
String s5 = "lo!";
System.out.println("s1 == \"hel\" + \"lo!\": " + (s1 == "hel" + "lo!"));
System.out.println("s1 == \"hel\" + s5: " + (s1 == "hel" + s5));