それらの基本的な違いはメモリ割り当てです。
最初のオプション、すなわち
String s1 = "hello";
このs1を使用すると、文字列リテラルとして呼び出され、コンパイル時に s1 のメモリが割り当てられます。
しかし、2番目のケースでは
String s2 = new String("hello");
この場合、s2 はhelloを表す String のオブジェクトとして呼び出されます。
最初のケースを使用して 2 つの文字列リテラルを作成しようとすると、これら 2 つのリテラルによって参照されるメモリは 1 つだけです。つまり、文字列リテラルは文字列プールの概念で機能しています。同じ内容の 2 番目の文字列リテラルを作成すると、新しいスペースを割り当てる代わりに、コンパイラは同じ参照を返します。したがって、 ==演算子を使用してこれら 2 つのリテラルを比較するとtrueになります。
しかし、2 番目のケースでは、毎回 JVM がそれぞれに対して新しいオブジェクトを作成します。equals()メソッドを使用してコンテンツを比較する必要がありますが、 ==演算子を使用する必要はありません。
2番目のケースを使用して新しい文字列オブジェクトを作成したいが、新しいオブジェクトが必要ない場合は、intern()メソッドを使用して同じオブジェクトを取得できます。
String s = "hello";
String s1 = new String("hello").intern();
System.out.println(s == s1);
この場合、新しいオブジェクトを作成する代わりに、JVM は同じ参照sを返します。したがって、出力はtrueになります