最近、私は面接の質問をブラッシュアップし、面接の質問のより古典的でコアなコンテンツのシリーズを作成し、それらをパブリックアカウントに公開し、基本的な知識を統合し、あなたと共有します。[プログラムの新しいビジョン]に引き続き注目してください。以下は、このシリーズの最初のものです。
ほとんどのインタビューの最初の質問は、オブジェクト指向について話しているのではなく、キャラクターについてです。この記事では、「==と等しい」の違いについてあらゆる側面から説明します。
概念の違い
文字列の比較(文字列のみであることに注意してください)では、==とequalsの違いには次の2つの点があります。
(1)「==」は、2つの変数またはインスタンスが同じメモリ空間を指しているかどうかを判断することです。
(2)「等しい」とは、2つの変数またはインスタンスが指すメモリ空間の値が同じかどうかを判断することです。
上記の説明は、抽象的な概念の観点からはあいまいです。上記の概念を明確に説明するために、最初にJVMメモリ割り当ての知識を簡単に理解しましょう。
オブジェクトのメモリ割り当てを作成する
JVMでは、メモリはヒープメモリとスタックメモリに分割されます。通常、newキーワードを使用してオブジェクトを作成する場合、オブジェクトのコンストラクターを呼び出してスペースを開き、オブジェクトデータをヒープメモリに格納すると同時に、対応する参照をスタックメモリに生成します。
String str = new String("程序新视界");
上記のコードでは、実際のStringオブジェクトはヒープメモリに格納され、str変数はオブジェクトを指す参照アドレスのみを保持します。後続のコードで呼び出す場合、スタックメモリ内のすべての参照(strが指すアドレス)が使用されます。
Stringがequalsメソッドを実装する方法
上記の概念を理解した後、equalsメソッドがStringでどのように実装されているかを見てみましょう。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
上記のコードには2つの部分があります。最初の部分は「==」と直接比較することです。比較オブジェクトの参照アドレスが等しいかどうかはすでにわかっています。つまり、2つのオブジェクトの参照アドレスが同じ場合、それらは同じです。
コードの2番目の部分は、受信オブジェクトがStringオブジェクトであるかどうかを決定します。それがStringオブジェクトであり、2つのStringオブジェクトの値のchar []配列の各要素が等しい場合、それらは等しいです。
上記のコードを読んだ後、違いを説明するときに「文字列のみに注意」というメモを追加する必要がある理由が理解できるでしょう。文字列のequalsメソッドは、equalsメソッドをオーバーライドするため、値を比較します。
要約すると、次の図にStringの比較を示します。
JavaのすべてのクラスはObjectオブジェクトから継承し、equalsメソッドもObjectオブジェクトで定義されています。
public boolean equals(Object obj) {
return (this == obj);
}
何を見た?Objectのequalsメソッドが参照アドレスであることが判明しました!したがって、「==は参照で比較する」と単純に言うと、equalsは対応する値への参照で比較しますが、これは誤りです。これは、Stringクラスのスコープに限定されます。
クラスを定義するときに、equalsメソッドがオーバーライドされない場合、Objectのデフォルトのequalsメソッドが使用されます。このメソッドを書き換える場合は、書き換えた方法で比較してみてくださいStringのequalsメソッドは書き換えた例のひとつです。
特別な文字列の定義
newの形式で定義されるだけでなく、Stringは等号割り当ての形式でも定義できます。
String str = "程序新视界";
これは非常に特殊な形式であり、オブジェクトはnewなしで生成できますが、newとは本質的に異なります。この形式の割り当てはJavaでは直接呼び出され、新しいプールのようにヒープに格納されるのではなく、定数プールに存在します。
そのような文字列を宣言するとき、JVMはまず定数プールで対応する値を持つオブジェクトを探します。その場合、それを現在の参照に割り当てます。つまり、元の参照と現在の参照ポイントが同じオブジェクトを指します。そうでない場合は、新しいオブジェクトが定数プールに作成されます。この形式で宣言された文字列の場合、値が等しい限り、複数の参照は同じオブジェクトを指します。
新しいフォームとは対照的にStringオブジェクトを作成することは、他のオブジェクトを作成することと同じです。呼び出しごとに新しいオブジェクトが生成されます。
検証例
以下の具体例を使用して、上記の結論を検証します。同時に、これらの検証の例は、面接の質問の内容になる場合もあります。
String x = "程序新视界";
String y = "程序新视界";
String z = new String("程序新视界");
System.out.println(x == y); // true
System.out.println(x == z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
最初の行では、オブジェクトは割り当てによって作成されるため、xに対応するオブジェクトが既にメモリに存在する場合、yオブジェクトを割り当てるときに、参照は元のオブジェクトを直接指します。したがって等しい。
2行目では、zはnewの形で作成されているため、新しいオブジェクトが作成されますが、ここでは2つのオブジェクトの参照アドレスが比較されているため、等しくありません。
3行目と4行目は文字列の実際の値を比較するため、等しくなります。
equalsメソッドをオーバーライドせずにオブジェクトの比較を見てみましょう。対応するエンティティクラスの定義と単体テストのメソッドは次のとおりです。
@Test
public void testObject(){
Person p1 = new Person("Tom");
Person p2 = new Person("Tom");
System.out.println(p1.equals(p2));
}
class Person{
public Person(String name){
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
上記のメソッドを実行すると、印刷結果が偽になります。
上記の2つの例を通じて、上記で説明した理論を検証しました。
概要
上記の分析の後、私は根本的なロジックを理解し、同様のインタビューの質問に遭遇したときに誰もが正確に答えることができると思います。
簡単に言えば、equalsによって比較されるものは参照であり、equalsによって比較されるものは値です。厳密に言うと間違っています。JVMオブジェクトのストレージ形式などの基礎となる実装原理を解決し、equalsメソッドを書き直すことによってのみ、暗記ではなく強みを反映できます。
次回の記事では、新しいStringの形式でのいくつかのオブジェクトと基になるロジックの作成について説明します。引き続き注目してください。
元のリンク:「インタビューの質問シリーズパート1:==と等しいの違いについて教えてください。あなたの答えは間違っているかもしれません」