Javaベースの(18)equalsメソッド

9070 ワード

Javaプログラムで2つの変数が等しいかどうかをテストするには、==演算子を使用する方法と、1つはequals関数を利用することである.
==演算子
==を用いて2つの変数が等しいか否かを判断する場合、2つの変数が基本型変数であり、いずれも数値型である場合、2つの変数の値が等しい限りtrueが戻る.
ただし、2つの参照変数について、同じオブジェクトを指す必要がある場合、==判断はtrueを返します.==比較タイプに親子関係のない2つのオブジェクトは使用できません.次の手順では、==を使用して、2つのタイプの変数が等しいかどうかを判断する結果を示します.
        int i = 65;
        float f = 65.0f;
        //   true
        System.out.println("65 65.0f    ?"+ (i==f));
        char c = 'A';
        //   true
        System.out.println("65 A    ?"+ (i==c));
        String str1 = new String("hello!");
        String str2 = new String("hello!");
;       //   false
        System.out.println("str1 str2    ?"+ (str1==str2));
        //String  Math       ,     
        //System.out.println("hello"== new Math());
65 65.0f    ?true
65 Atrue
str1 str2    ?false

結果から,65と65.0 fと’A’は等しいことが分かった.しかし、str 1およびstr 2の場合、これらはいずれも参照型変数であり、それぞれ2つの異なるStringオブジェクトを指すため、str 1およびstr 2の2つの変数は等しくない.
では、次のように変更します.
String str1 = "hello!";
String str2 = "hello!";
System.out.println("str1 str2    ?"+ (str1==str2));
    :
str1 str2    ?true

ここでの出力は、2つの文字列文字が1つのオブジェクトとして保存されていることを示します.つまり、上のコードはStringオブジェクトを1つしか作成していません.
では、「hello」とnew String(「hello」)の具体的な違いはどこにあるのでしょうか.
ここまで言うと、ちょうど面接の質問に答えに来ました.
String s=new String(「xyz」)はいくつのオブジェクトを作成しますか?
Javaプログラムが「hello」などの文字列の直接量を直接使用する場合、JVMは定数プールを使用して文字列を管理します.
String str1 = “hello”;この行のコードが実行されるとき、JAVA仮想マシンはまず文字列プールに「hello」という値のオブジェクトが存在するかどうかを検索し、その判断根拠はStringクラスequals(Object obj)メソッドの戻り値である.ある場合は、新しいオブジェクトは作成されず、既存のオブジェクトの参照を直接返します.ない場合は、このオブジェクトを作成してから文字列プールに追加し、参照を返します.str 1とstr 2のテキスト文字列は同じであるため、文字列オブジェクト「hello」は1つしか作成されません.
Java内のすべての文字列文字[文字列定数]はStringのオブジェクトです.
String str1 = new String(“hello”);この行のコードが実行されると、JVMはまず定数プールにStringオブジェクト「hello」を作成し、Stringクラスのコンストラクタで新しいStringオブジェクトを作成し、新しく作成したStringオブジェクトはスタックメモリに保存されます.したがって、この行のコードは実際に2つのオブジェクトを生成します.
では、String str=「a」+「b」+「c」はいくつのオブジェクトを作成しますか?答えは一つです.コンパイラは、「a」+「b」+「c」というコードをコンパイル中に1つの文に最適化します.すなわち、文字列が1つの文字列に結合することは(String str=「abc」)に相当します.つまり、コードコンパイル後の実行中に一時オブジェクトが1つしか生成されません.
equals関数
JVM定数プールは、同じ文字列定数が1つしかないことを保証します.2つの異なるオブジェクトを指す参照変数について、それらの「値」が等しいかどうかを判断して2つの変数が等しいかどうかを決定するだけであれば、Stringオブジェクトのequalsメソッドを用いて判断することができる.たとえば、str 1とstr 2を比較する方法を上のコードで書き換えることができます.
        String str1 = new String("hello!");
        String str2 = new String("hello!");
        System.out.println(str1.equals(str2));
true

equalsメソッドはどこですか
equalsメソッドはObjectクラスが提供するインスタンスメソッドであり、Objectクラスはすべてのクラスの親であるため、すべてのクラスにequals関数があり、すべての参照変数が他の変数と等しいかどうかを判断するために呼び出されます.
Stringクラスのequalsメソッドは、2つの文字列が等しいと判断する基準は、2つの文字列に含まれる文字列のシーケンスが同じであれば、equalsメソッドによってtrueが返され、そうでなければfalseが返されます.
総じてequalsの役割は、2つのオブジェクトの内容が等しいかどうかを比較することであり、2人の顔が同じかどうかを比較することであり、比較された2つのオブジェクトは独立している.通常、2つのオブジェクトの内容が等しい場合は、2つの条件を満たす必要があります.
  • オブジェクトのタイプは同じ(instanceof演算子で比較可能)
  • です.
  • の2つのオブジェクトのメンバー変数の値は、同じ
  • です.
    equalsメソッドの書き換え
    まず、equalsを使用して2つのオブジェクトのコードを比較します.
    class Person{
        String name;
        int age;
    }
    public class Test {
        public static void main(String[] args){
            Person p1 = new Person();
            Person p2 = new Person();
            System.out.println(p1.equals(p2));
        }
    false

    equalsを使用して2つのオブジェクトを判断する基準は、実際には==演算子と区別されず、同じように2つの参照変数が同じオブジェクトを指している場合にtrueが返される(StringはObjectのequalsメソッドを書き換えたため、上のコードはtrueが返される)ため、このObjectが提供するequalsメソッドはあまり役に立たず、カスタムの等しい基準を採用したい場合は、equalsメソッドを書き換えることで実現できます.
    上記の2つの要件に基づいて、次のプログラムではequalsの書き換え方法を示します.
    class Person{
        String name;
        int age;
    
        public boolean equals(Object obj){
            //            ,this   equals       
            if(this == obj){
                return true;
            }
            //  obj     this    ,this Person  
            boolean b = obj instanceof Person;
            //    
            if(b){
                //    
                Person p = (Person)obj;
                //               
                if(this.age == p.age&&this.name.equals(p.name)){
                    return true;
                }
                else{
                    return false;
                }
            }
    
            else{
                return false;
            }
    
        }
    public class Test {
        public static void main(String[] args){
            Person p1 = new Person();
            p1.name = "zhangsan";
            p1.age = 10;
    
            Person p2 = new Person();
            p2.name = "lisi";
            p2.age = 10;
    
            Person p3 = new Person();
            p3.name = "zhangsan";
            p3.age = 10;
            System.out.println(p1.equals(p2));
            System.out.println(p1.equals(p3));
        }
    
    }
    
    false
    true

    コードで==演算子を用いずにthis.name.equals(p.name)で両者が等しいかどうかを比較するのは,nameがStringタイプ参照変数であるため,Stringはequalsメソッドを書き換え,両者の内容が同じかどうかを直接比較することができる.
    ==とequalsメソッドの違い
    ==オペレータは、2つの変数の値が等しいかどうか、すなわち、変数に対応するメモリに格納されている値が同じかどうかを比較するために使用されます.1つの変数が指すデータがオブジェクトタイプである場合、オブジェクト自体が1つのメモリ(スタックメモリ)を占有し、変数が1つのメモリ(スタックメモリ)を占有し、例えばObject obj=new Object()である.変数objに対応するメモリに格納される数値は、オブジェクトが占有するメモリのヘッダアドレスであり、==オペレータは、2つの変数がスタックメモリの同じアドレスを指しているかどうか、すなわち、2つの変数に対応するメモリ(スタックメモリ)の数値が等しいかどうかを比較するために使用される.
    equalsメソッドは、主に2つの独立したオブジェクトの内容が同じかどうか、まずタイプが同じかどうか、次にメンバー変数が同じかどうかを比較するために使用されます.