CodeGym /Java Blog /ランダム /Java での文字列の比較と等しい比較
John Squirrels
レベル 41
San Francisco

Java での文字列の比較と等しい比較

ランダム グループに公開済み
やあ!今日は非常に重要で興味深いトピック、つまりオブジェクトとオブジェクトの比較 (文字列と等しい値の比較) について説明します。それでは、Java では、オブジェクトAがオブジェクトBと正確に等しいのはいつでしょうか? 例を書いてみましょう:

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {
      
       Car car1 = new Car();
       car1.model = "Ferrari";
       car1.maxSpeed = 300;

       Car car2 = new Car();
       car2.model = "Ferrari";
       car2.maxSpeed = 300;

       System.out.println(car1 == car2);
   }
}
コンソール出力: false 待って、停止します。なぜこの 2 台の車は同等ではないのでしょうか? それらに同じプロパティを割り当てましたが、比較の結果は false でした。答えは簡単です。==演算子は、オブジェクトのプロパティではなく、オブジェクト参照を比較します。2 つのオブジェクトに同じ値を持つフィールドが 500 個ある場合もありますが、それらを比較すると false が返されます。結局のところ、car1car2を参照してください。2 つの異なるオブジェクト、つまり 2 つの異なるアドレスを指します。人々を比較する状況を想像してください。確かに、世界のどこかに、あなたと同じ名前、目の色、年齢、身長、髪の色などを共有する人がいます。そのため、あなたは多くの点で似ていますが、それでも双子ではありません。そして、明らかに違います。同じ人です。
等しいものと文字列の比較 - 2
== 演算子は、2 つのオブジェクトを比較するために使用する場合、これとほぼ同じロジックを使用します。しかし、プログラムで別のロジックを使用する必要がある場合はどうすればよいでしょうか? たとえば、プログラムで DNA 分析を実行するとします。2人の人の遺伝コードを比較し、双子かどうかを判定します。

public class Man {

   int geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = 1111222233;

       Man man2 = new Man();
       man2.geneticCode = 1111222233;

       System.out.println(man1 == man2);
   }
}
コンソール出力: false 同じ論理結果が得られますが (あまり変更していないため)、そのロジックは役に立ちません。結局のところ、現実の生活では、DNA 分析により、目の前に双子がいることを 100% 保証する必要があります。しかし、私たちのプログラムと==演算子は反対のことを示します。この動作を変更して、DNA が一致したときにプログラムが正しい結果を出力するようにするにはどうすればよいでしょうか? Java には、このための特別なメソッドequals()があります。前に説明したtoString()メソッドと同様に、equals() はObjectクラスに属します。これは Java で最も重要なクラスであり、他のすべてのクラスの派生元のクラスです。ただし等しい()それ自体でプログラムの動作が変わるわけではありません。

public class Man {

   String geneticCode;

   public static void main(String[] args) {

       Man man1 = new Man();
       man1.geneticCode = "111122223333";

       Man man2 = new Man();
       man2.geneticCode = "111122223333";

       System.out.println(man1.equals(man2));
   }
}
コンソール出力: false まったく同じ結果ですが、このメソッドは何に必要なのでしょうか? :/ すべて簡単です。ここでの問題は、現在このメソッドがObjectクラスに実装されているので使用していることです。Objectクラスのコードを調べてメソッドの実装を見ると、次のようになります。

public boolean equals(Object obj) {
   return (this == obj);
}
それが、プログラムの動作が変わっていない理由です。まったく同じ==演算子 (参照を比較する) が、 Objectクラスのequals()メソッド内で使用されます。ただし、このメソッドの重要な点は、オーバーライドできることです。オーバーライドとは、Manクラスに独自のquals()メソッドを記述し、必要な動作を与えることを意味します。現時点では、 man1.equals(man2) がman1 == man2と本質的に同等であるという事実が気に入らないのです。この状況では次のようにします。

public class Man { 

   int dnaCode; 

   public boolean equals(Man man) { 
       return this.dnaCode ==  man.dnaCode; 

   } 

   public static void main(String[] args) { 

       Man man1 = new Man(); 
       man1.dnaCode = 1111222233; 

       Man man2 = new Man(); 
       man2.dnaCode = 1111222233; 

       System.out.println(man1.equals(man2)); 

   } 
} 
コンソール出力: true 今度は、まったく異なる結果が得られます。独自のequals()メソッドを作成し、標準のメソッドの代わりにそれを使用することで、正しい動作が生成されました。2人が同じDNAを持っている場合、プログラムは「DNA分析により、彼らが双子であることが証明されました」と報告し、trueを返します。クラスでequals()メソッドをオーバーライドすることで、必要なオブジェクト比較ロジックを簡単に作成できます。実際、オブジェクトの比較についてはまだ触れたばかりです。この先には、このトピックに関する大きな独立したレッスンがまだ残っています(興味がある場合は、ざっと読んでください)。

Java での文字列の比較

文字列の比較を他のものと分けて考えるのはなぜでしょうか? 実際には、文字列はそれ自体がプログラミングの主題です。まず、これまでに作成されたすべての Java プログラムを取り上げると、そのプログラム内のオブジェクトの約 25% が文字列であることがわかります。したがって、このトピックは非常に重要です。第 2 に、文字列を比較するプロセスは他のオブジェクトとは大きく異なります。簡単な例を考えてみましょう。

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
コンソール出力: false しかし、なぜ false が返されたのでしょうか? 結局のところ、文字列は一字一句まったく同じです :/ 理由は推測できたかもしれませんが、==演算子が参照を比較するためです。明らかに、s1s2 はメモリ内で異なるアドレスを持っています。そう考えた場合は、例を作り直してみましょう。

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       System.out.println(s1 == s2);
   }
}
ここで再び 2 つの参照ができましたが、結果はまったく逆になります。 コンソール出力: true どうしようもなく混乱していますか? 何が起こっているのか見てみましょう。==演算子は実際にメモリ アドレスを比較します。これは常に真実であり、疑う必要はありません。つまり、s1 == s2 がtrue を返す場合、これら 2 つの文字列は同じアドレスを持つことになります。そして実際、これは真実です!文字列を保存するための特別なメモリ領域、文字列プールを紹介します。
等しいものと文字列の比較 - 3
文字列プールは、プログラムで作成したすべての文字列値を保存する領域です。なぜ作成されたのでしょうか? 前に述べたように、文字列はすべてのオブジェクトの大きな割合を占めます。大規模なプログラムでは、大量の文字列が作成されます。文字列プールはメモリを節約するために作成されました。文字列はそこに配置され、その後作成される文字列はメモリの同じ領域を参照します。毎回追加のメモリを割り当てる必要はありません。String = "....."と書き込むたびに、プログラムは文字列プールに同一の文字列があるかどうかをチェックします。存在する場合、新しい文字列は作成されません。そして、新しい参照は、文字列プール内の同じアドレス (同一の文字列が存在する場所) を指します。それで、私たちが書いたとき

String s1 = "CodeGym is the best website for learning Java!";
String s2 = "CodeGym is the best website for learning Java!";
s2 はs1と同じ場所を指します。最初のステートメントは、文字列プールに新しい文字列を作成します。2 番目のステートメントは、単にs1と同じメモリ領域を参照します。さらに 500 個の同一の文字列を作成しても、結果は変わりません。ちょっと待って。それが本当なら、なぜこの例が以前は機能しなかったのでしょうか?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2);
   }
}
あなたの直感でその理由がすでにわかっていると思います =) さらに読み進める前に推測してみてください。これら 2 つの文字列が異なる方法で宣言されていることがわかります。1 つは新しい演算子を使用したもの、もう 1 つは新しい演算子を使用しないものです。その理由はここにあります。new演算子を使用してオブジェクトを作成すると、そのオブジェクトに新しいメモリ領域が強制的に割り当てられます。また、 newを使用して作成された文字列は、最終的に文字列プールには入りません。たとえそのテキストが文字列プール内の文字列と完全に一致したとしても、別のオブジェクトになります。つまり、次のコードを書くとします。

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = "CodeGym is the best website for learning Java!";
       String s3 = new String("CodeGym is the best website for learning Java!");
   }
}
記憶では次のようになります。
等しいものと文字列の比較 - 4
そして、 newを使用して新しいオブジェクトを作成するたびに、新しい文字列内のテキストが同じであっても、メモリの新しい領域が割り当てられます。==演算子を理解したようです。しかし、私たちの新しい知り合い、equals()メソッドについてはどうでしょうか?

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1.equals(s2));
   }
}
コンソール出力: true 興味深いですね。s1s2 がメモリ内の異なる領域を指していることは確かです。しかし、equals()メソッドは依然としてそれらが等しいことを示します。なぜ?以前、equals()メソッドをオーバーライドしてオブジェクトを任意に比較できると述べたことを覚えていますか? それがまさにStringクラスで行われたことです。これは、equals()をオーバーライドします。方法。また、参照を比較する代わりに、文字列内の文字のシーケンスを比較します。テキストが同じであれば、その作成方法や保存場所 (文字列プールかメモリの別の領域か) は関係ありません。比較の結果は true になります。ちなみに、Java では大文字と小文字を区別しない文字列比較を実行できます。通常、文字列の 1 つがすべて大文字である場合、比較の結果は false になります。

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CODEGYM IS THE BEST WEBSITE FOR LEARNING JAVA!");
       System.out.println(s1.equals(s2));
   }
}
コンソール出力: false 大文字と小文字を区別しない比較の場合、StringクラスにはequalsIgnoreCase()メソッドがあります。大文字と小文字を比較するのではなく、特定の文字のシーケンスのみを比較したい場合に使用できます。たとえば、これは 2 つのアドレスを比較する場合に役立ちます。

public class Main {

   public static void main(String[] args) {

       String address1 = "2311 Broadway Street, San Francisco";
       String address2 = new String("2311 BROADWAY STREET, SAN FRANCISCO");
       System.out.println(address1.equalsIgnoreCase(address2));
   }
}
この場合、明らかに同じアドレスについて話しているので、equalsIgnoreCase()メソッドを使用するのが理にかなっています。

String.intern() メソッド

Stringクラスには、もう 1 つ注意が必要なメソッドがあります: intern () ; intern ()メソッドは文字列プールを直接操作します。ある文字列に対して intern()メソッドを呼び出すと、次のようになります。
  • 文字列プールに一致する文字列があるかどうかを確認します
  • 存在する場合は、プール内の文字列への参照を返します。
  • そうでない場合は、文字列を文字列プールに追加し、それへの参照を返します。
new を使用して取得した文字列参照に対してintern()メソッド を使用した後、 ==演算子を使用して文字列プールからの文字列参照と比較 できます。

public class Main {

   public static void main(String[] args) {

       String s1 = "CodeGym is the best website for learning Java!";
       String s2 = new String("CodeGym is the best website for learning Java!");
       System.out.println(s1 == s2.intern());
   }
}
コンソール出力: true以前にintern() を使用せずにこれらの文字列を比較したとき、結果は false でした。ここで、intern()メソッドは、文字列「CodeGym は Java を学習するのに最適なサイトです!」かどうかをチェックします。文字列プール内にあります。もちろん、それは次のとおりです。

String s1 = "CodeGym is the best website for learning Java!";
s1とs2.intern()によって返された参照が同じメモリ領域を指している かどうかを確認します。そしてもちろん、彼らはそうします:) 要約すると、次の重要なルールを覚えて適用してください: 文字列を比較する場合は常に、equals()メソッドを使用してください。文字列を比較するときは、ほとんどの場合、参照やメモリ領域などではなく、その文字を比較することを意味します。equals ()メソッドは、必要なことを正確に実行します。 学んだことをさらに強化するには、Java コースのビデオ レッスンを視聴することをお勧めします。

さらに読む:

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION