equals メソッドと ==
の違い まず第一に、String はオブジェクトとしても基本型としても使用できることは誰もが知っています。ここで言う基本型としての使用とは、String s = "Hello" などの使用方法のみを指します。 int i = 1; など、基本型 int と同様に使用されます。これをオブジェクトとして使用することは、String s = new String("Hello") などの new キーワードを使用して新しいオブジェクトを作成することを指します。ただし、その内部アクションは実際にオブジェクトを作成します。これについては後で説明します。
次に、String オブジェクトの比較方法を理解する必要があります。 Java のオブジェクト間の比較には 2 つの概念があります。次に、String オブジェクトを示します。1 つは、「==」を使用して比較することです。つまり、2 つの For String 型変数を比較します。変数が同じ String オブジェクトを参照している (つまり、同じメモリ ヒープを指している) 場合、「==」比較の結果は true になります。もう 1 つは、比較に Object オブジェクトの equals() メソッドを使用する方法です。String オブジェクトは Object から継承され、equals() メソッドはオーバーライドされます。 2 つの String オブジェクトが、equals() メソッドを通じて比較される場合、String オブジェクトによってカプセル化された文字列の内容が実際に比較されます。つまり、2 つの String オブジェクトによってカプセル化された文字列の内容が同じである場合 (同じ場合を含む)、その後、equals() メソッドは true を返します。
ここで、String オブジェクトの作成の詳細な分析を開始します:
1. ///////////////////// //// /////////////////////////////////////////
文字列s1 = new String( "Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2) ));
上記のコード スニペットの出力結果は次のとおりです:
false
true
この結果は理解しやすいと思います。2 つの String 型変数 s1 と s2 は、それぞれ new キーワードを通じて新しい String オブジェクトを作成します。新しいキー 作成されたオブジェクトごとに新しい独立したメモリ ヒープを割り当てます。したがって、「==」で同じオブジェクトを参照しているかどうかを比較すると false が返されます。 2 つのオブジェクトによってカプセル化された文字列の内容がまったく同じであるため、equals() メソッドを通じて比較すると true が返されます。
2、/////////////////////////////////////////// /// ///////////////////////////////////////////
String s1 = new String("Hello ");
String s2 = s1;
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
上記のコード スニペットの出力結果
true
true
この結果は、変数 s1 が new キーワードを通じて新しい String オブジェクトを作成することをよく理解する必要がありますが、ここでは s2 は new キーワードを通じて新しい String オブジェクトを作成せず、s1 を直接割り当てます。 s2 には s1 の参照が s2 に割り当てられているため、s2 によって参照されるオブジェクトは実際には s1 によって参照されるオブジェクトになります。したがって、「==」と比較すると true が返されます。これらはすべて同じオブジェクトを参照しているため、equals() メソッドで比較すると、実際には同じオブジェクトを比較しており、それ自体と等しい必要があります。
3、//////////////////////////////////////////// // /////////////////////////////////////////////////
文字列 s1 = "こんにちは";
文字列 s2 = "こんにちは";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
上記のコードセグメントの出力結果は次のとおりです:
true
true
なぜこの結果になったのでしょうか?それでは、それを分析してみましょう。まず、これら 2 つの String オブジェクトは new キーワードによって作成されるのではなく、基本タイプとして使用されるため、仮想マシンはこれら 2 つの String オブジェクトに対して新しいメモリ ヒープを割り当てず、String バッファ プールに割り当てます。探す。まず、S1 を検索して、文字列バッファ プール内の「Hello」と同じ値を持つ文字列オブジェクトを見つけます。この時点では、文字列バッファ プールは空であり、同じ値を持つ文字列オブジェクトはありません。新しい String("Hello"); です。次に、この String オブジェクトの参照を s1 に割り当てます。次に、S2 で「Hello」と同じ値を持つ STRING オブジェクトを見つけて String バッファ プールを見つけます。このとき、仮想マシンは同じ値を持つ String オブジェクトを見つけます。 S1.同じ値を持つオブジェクトが見つかったので、仮想マシンはこれに対して新しい String オブジェクトを作成せず、既存の String オブジェクトの参照を s2 に直接割り当てます。
s1 と s2 は同じ String オブジェクトを参照している、つまりそれら自体と等しいため、上記の 2 つの比較メソッドは true を返します。
この時点で、String オブジェクトの基本概念は理解できたはずです。ここで要約しましょう:
基本的な型として String を使用する:
1. String が基本型として使用される場合、この String オブジェクトは String バッファー プールによって所有されているものとみなされます。
2. String が基本タイプとして使用されており、現時点で同じ指定値を持つ String オブジェクトが String バッファー プールにない場合、仮想マシンはこれに対して新しい String オブジェクトを作成し、String バッファー プールに保存します。
3. String が基本タイプとして使用されており、この時点で String バッファー プール内に同じ指定値を持つ String オブジェクトが存在する場合、仮想マシンはこれに対して新しい String オブジェクトを作成せず、そのオブジェクトへの参照を直接返します。既存の String オブジェクト。
文字列をオブジェクトとして使用します:
1. String がオブジェクトとして使用される場合、仮想マシンはこのオブジェクトに対して新しい String オブジェクトを作成します。つまり、このオブジェクトに新しいメモリ ヒープが割り当てられます。また、このオブジェクトは String バッファ プールによって所有されません。つまり、独立しています。 。
上記を理解した後、次のコード スニペットを見てください:
4、/////////////////////////////// /// ////////////////////////////////////////////
String s1 = "Hello";
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2)) ;
上 コードセグメントの出力結果は次のとおりです:
false
true
上記のまとめをもとに分析しました。最初の行では基本型として String を使用しているため、s1 によって参照されるオブジェクトは String バッファー プールに属します。この時点では、String バッファー プール内に同じ値を持つ String オブジェクトがないため、仮想マシンはこのために新しい String オブジェクト、つまり new String("Hello"); を作成します。 2 行目では String をオブジェクトとして使用しているため、s2 によって参照されるオブジェクトは String バッファー プールに属さず、独立しています。 new キーワードを使用すると、仮想マシンはこの目的のために新しい String オブジェクトを作成します。つまり、新しいメモリ ヒープを割り当てます。したがって、s1 と s2 は同じオブジェクトを参照しておらず、独立して存在するため、「==」比較の結果は false になります。 2 つのオブジェクトによってカプセル化された文字列の内容がまったく同じであるため、equals() メソッドは true を返します。
さて、皆さんは String オブジェクトが何であるかを完全に理解できたと思います:) しかし、String オブジェクトにはさらに深い応用があるので、これで終わりではありません。
ここでは、String オブジェクトの intern() メソッドのアプリケーションを分析します。
intern() メソッドは、文字列オブジェクトの正規表現、つまり文字列と同じ内容を持つ文字列を返しますが、文字列用の一意の文字列バッファ プールから。これは少しくどいように聞こえますが、実際にはそのメカニズムは次のとおりです:
String s = new String("Hello");
s = s.intern();
上記のコード スニペットの関数実装は次のようになります。次のコードセグメントを単純に見てみましょう:
String s = "Hello";
また疑問に思っているのではないでしょうか?次に、最初に 2 番目のコード スニペットを見てみましょう。 2 番目のコード スニペットの意味は、String バッファ プールから同じ値を持つ String オブジェクトへの参照を取得し、それを s に割り当てることです。 String バッファー プール内に同じ値を持つ String オブジェクトがない場合は、その中に新しい String オブジェクトが作成されます。では、最初のコードは何を意味するのでしょうか? new キーワードを使用して作成されたオブジェクトに対しては、仮想マシンが新しいメモリ ヒープを割り当てることがわかっています。同じ内容のオブジェクトを簡単に作成すると、その内容はまったく同じであっても、仮想マシンはそのオブジェクトに多くの新しいメモリ ヒープも割り当てます。 String オブジェクトを例にとると、同じ内容 (new String("Hello")) を持つ 10 個の String オブジェクトが連続して作成された場合、仮想マシンはそれらに 10 個の独立したメモリ ヒープを割り当てます。作成された String オブジェクトの文字列コンテンツが非常に大きいと仮定します。Stirng オブジェクトが 1M の文字列コンテンツをカプセル化すると、10 個の同一の String オブジェクトを作成すると、9M のメモリ領域が無駄に消費されます。 String は最終クラスであり、カプセル化されるものは文字列定数であることがわかっています。したがって、String オブジェクトの内部 (文字列) 値は作成後に変更できないため、String オブジェクトは共有できます。したがって、先ほど述べた仮定では、同じ内容で作成した 10 個の String オブジェクトについて、実際には 1 つの String オブジェクトを作成するだけで済み、その後、そのオブジェクトは他の String 変数によって共有されます。このメカニズムを実装する唯一の簡単な方法は、String バッファ プールを使用することです。String バッファ プールには同じ内容を持つ String オブジェクトが存在しないためです。 intern() メソッドは、このメカニズムを使用する方法です。インスタンス化された String オブジェクトで intern() メソッドを呼び出した後、仮想マシンは String バッファ プール内でこの Stirng オブジェクトによってカプセル化された文字列コンテンツと同じ値を持つ String オブジェクトを検索し、元の String オブジェクトへの参照を割り当てます。 . 文字列型変数。この String オブジェクトによってカプセル化された文字列コンテンツと同じ値を持つ String オブジェクトが String バッファ プールにない場合、仮想マシンは新しい String オブジェクトを作成し、その参照を元の String オブジェクトを参照する String 型変数に割り当てます。 。このようにして、同じ String オブジェクトを共有するという目的が達成され、new キーワードによって作成された元の String オブジェクトはガベージ コレクターによって破棄され、リサイクルされます。これにより、メモリ使用量が削減され、パフォーマンスが向上するだけでなく、同じ String オブジェクトが共有されるため、String オブジェクトの比較がより便利になります。そのため、2 つの String オブジェクトが同じかどうかを判断するには、" == を使用するだけで比較できます。これは、String オブジェクトのquals() メソッドが文字列の内容を逆アセンブルしてから 1 つずつ比較するため、使いやすいだけでなく、パフォーマンスも向上します。 、文字列の内容が非常に大きい場合、この比較アクションによりパフォーマンスが大幅に低下します。この点に関しては、誰もが具体的なアプリケーションについて少し漠然としているかもしれません。そこで、上記の概念を説明するために簡単な例を挙げましょう:
クラスがあると仮定すると、クラスにはメッセージを記録するメソッドがあります。この方法では、ユーザーからのメッセージ (メッセージの内容が多く、繰り返し率が高い場合を想定) を受信した順にリストに記録します。友達の中には次のように設計する人もいると思います:
import java.util.*;
public class Messages {
ArrayListmessages = new ArrayList();
public void Record(String msg) {
messages.add (msg );
}
public List getMessages() {
returnmessages;
}
}
このデザインは良いですか?同じメッセージを Record() メソッドに繰り返し送信し (メッセージは異なるユーザーから送信されているため、各メッセージは新しい String("...") と見なすことができます)、メッセージの内容が大きいと仮定すると、この設計は内容は同じですが、メッセージ リスト内のすべてのレコードは新しく作成された独立した String オブジェクトであるため、これはメモリ領域の多大な無駄です。では、どのように最適化できるのでしょうか?実際は非常に簡単です。次の最適化された例を参照してください:
import java.util.*;
public class Messages {
ArrayListmessages = new ArrayList();
public void Record( String msg) {
messages.add(msg.intern());
}
public List getMessages() {
returnmessages;
}
}
ご覧のとおり、元のメッセージです。 Record() メソッドの add(msg); コード セグメントはmessages.add(msg.intern()); になり、msg パラメータに対して intern() メソッドのみが呼び出されるため、重複したメッセージは共有メカニズムになります。メモリ消費量を削減し、パフォーマンスを向上させます。
この例は確かに少し突飛ですが、上記の概念を説明するためのものです。
この時点で、String オブジェクトの霧は解消されました。これらの概念を念頭に置いておく限り、将来の複雑な String アプリケーションもこれに基づいて分析できます。
String が、equals メソッドと == を使用してそれぞれ比較する方法に関する詳細な関連記事については、PHP 中国語 Web サイトに注目してください。