overriding predefined methods java
このチュートリアルでは、Javaでequals()、hashCode()、compareTo()などの事前定義されたメソッドをオーバーライドする方法を例を挙げて説明します。
前のチュートリアルでは、Javaでのランタイムポリモーフィズムについて説明しました。 Javaのランタイムポリモーフィズムは、メソッドのオーバーライドを使用して実装されます。メソッドのオーバーライドには、サブクラスの親クラスメソッドの再定義が含まれます。
Javaには、equals()、hashCode()、compareTo()、toString()などのさまざまな定義済みメソッドがあり、それらが属するクラスに関係なく、一般的なオブジェクトに一般的に使用されます。ただし、これらのメソッドをすべてのオブジェクトで機能させるには、これらのメソッドをオーバーライドするか、実装を再定義して、必要なデータを処理できるようにする必要があります。
=> ゼロからJavaを学ぶには、ここにアクセスしてください。
このチュートリアルでは、これらのメソッドをオーバーライドしない場合の結果とともに、これらすべてのメソッドのオーバーライドについて説明します。
学習内容:
- Javaのequals()メソッドとhashCode()メソッドのオーバーライド
- Javaで静的メソッドをオーバーライドする
- JavaでcompareTo()をオーバーライドする
- JavaでtoString()メソッドをオーバーライドする
- よくある質問
- 結論
- 推奨読書
Javaのequals()メソッドとhashCode()メソッドのオーバーライド
Javaのequals()メソッドを使用して、2つのオブジェクトを比較します。このメソッドは、オブジェクトが等しい場合はtrueを返し、等しくない場合はfalseを返します。
2つのオブジェクトの同等性を比較するには、2つの方法が使用されます。
#1)浅い比較
どんな種類のメールがありますか
浅い比較は、「java.lang.Object」クラスで定義されているequals()メソッドのデフォルトの実装です。この実装の一部として、equals()メソッドは、比較される2つのオブジェクトに同じオブジェクトを参照する参照があるかどうかを確認します。
これは、obj1とobj2が2つのオブジェクトである場合、equals()メソッドのデフォルトの実装(浅い比較)は、obj1とobj2の参照が同じオブジェクトからのものであるかどうかのみをチェックすることを意味します。
浅い比較では、データの内容は比較されません。
#2)深い比較
深い比較では、各オブジェクトのデータメンバーを比較します。つまり、オブジェクトは状態に関して比較されます。そのため、オブジェクトをその内容を含む深いレベルで比較します。
深い比較を使用してオブジェクトを比較するには、通常、equals()メソッドをオーバーライドします。
次に、次のJavaプログラムについて考えてみます。
class Complex { private double r, i; //declare real and imaginary component as private public Complex(double r, double i) { //constructor this.r = r; this.i = i; } } public class Main { public static void main(String() args) { Complex c1 = new Complex(5, 10); //c1 object Complex c2 = new Complex(5, 10); //c2 object if (c1 == c2) { System.out.println('Two Complex objects are Equal '); } else { System.out.println('Two Complex objects are not Equal '); } } }
出力:
上記のプログラムの出力を見ると、2つのオブジェクトの内容が同じであっても、オブジェクトが等しくないことがわかります。これは、等価性がチェックされると、2つのオブジェクトc1とc2が同じオブジェクトを参照しているかどうかが判断されるためです。
プログラムに見られるように、c1とc2は2つの異なるオブジェクトであるため、それらは異なる参照であり、その結果、そのようになります。
次に、3番目の参照c3を作成し、次のようにc1と同等にします。
複素数c3 = c1;
この場合、c3とc1は同じオブジェクトを参照するため、(c3 == c1)はtrueを返します。
上記のプログラムが行ったことは、浅い比較でした。では、2つのオブジェクトがコンテンツに関して同じであるかどうかをどのように確認するのでしょうか。
ここでは、詳細な比較を行います。この目的のために、equals()メソッドをオーバーライドします。
次のプログラムは、equals()メソッドのオーバーライドを示しています。同じComplexクラスを使用します。
class Complex { private double r, i; public Complex(double r, double i) { this.r = r; this.i = i; } // override equals () method to compare two complex objects @Override public boolean equals(Object obj) { // returns true=>object is compared to itself if (obj == this) { return true; } //return false if obj is not an instance of Complex class if (!(obj instanceof Complex)) { return false; } // typecast obj to Complex type Complex c = (Complex) obj; // Compare the contents of two objects and return value return Double.compare(r, c.r) == 0 && Double.compare(i, c.i) == 0; } } public class Main { public static void main(String() args) { Complex c1 = new Complex(5, 10); Complex c2 = new Complex(5, 10); if (c1.equals(c2)) { System.out.println('Complex objects c1 and c2 are Equal '); } else { System.out.println('Complex objects c1 and c2 are not Equal '); } } }
出力:
オーバーライドされたequals()メソッドができたので、2つのオブジェクトを比較すると、内容が同じであるため、出力は2つのオブジェクトが等しいことを示しています。オーバーライドされたequals()メソッドに注意してください。ここでは、両方のオブジェクトが同じ参照を持っているかどうかを確認します。そうでない場合は、これらのオブジェクトの内容を個別にチェックします。
Javaでは、equals()メソッドをオーバーライドするときはいつでも、hashCode()メソッドもオーバーライドすることをお勧めします。これは、hashCode()メソッドをオーバーライドしない場合、各オブジェクトが異なるhashCodeを持つ可能性があるためです。
これは一般的なオブジェクトに干渉しない可能性がありますが、HashTable、HashSet、HashMapなどの特定のハッシュベースのコレクションが正しく機能しない場合があります。
次のプログラムは、equals()メソッドとhashCode()メソッドがオーバーライドされていることを示しています。
import java.io.*; import java.util.*; class EqualsHashCode { String name; int id; EqualsHashCode(String name, int id) { this.name = name; this.id = id; } @Override public boolean equals(Object obj) @Override public int hashCode() { // return current object's id as hashCode return this.id; } } class Main { public static void main (String() args) { // create two objects with same state EqualsHashCode e1 = new EqualsHashCode('Java', 1); EqualsHashCode e2 = new EqualsHashCode('Java', 1); //update the objects Map map = new HashMap(); map.put(e1, 'C++'); map.put(e2, 'Python'); //display contents for(EqualsHashCode eh : map.keySet()) { System.out.println(map.get(eh).toString()); } } }
出力:
このプログラムでは、hashMapを使用します。 equals()メソッドとhashCode()メソッドの両方をオーバーライドしました。したがって、map.put(e1、“ C ++”)と言うと、バケットの場所にハッシュされます。次に、map.put(e2、「Python」)を呼び出します。今回は同じバケットにハッシュし、前の値を置き換えます。これは、hashCode()メソッドをオーバーライドしたためです。
Javaで静的メソッドをオーバーライドする
Javaで静的メソッドをオーバーライドできますか?
Javaで静的メソッドをオーバーライドすることに関する限り、この質問への直接の回答は「いいえ」です。静的メソッドをオーバーライドすることはできません。
静的メソッドは、クラス名自体を使用して呼び出されます。静的メソッドを呼び出すためのオブジェクトは必要ありません。したがって、サブクラスで同じプロトタイプを持つメソッドを宣言したとしても、それをオーバーライドと呼ぶことはできません。代わりに、静的メソッドの親クラス定義を非表示にしているだけです。
次のJavaプログラムは、継承システムの静的メソッドと非静的メソッドを、実行時の動作とともに示しています。
class Parent { // Parent class static method cannot be overridden by Child public static void display() { System.out.println('Parent class::static display()'); } // parent class non-static print method to be overridden by Child public void print() { System.out.println('Parent class::non-static print()'); } } // Subclass class Child extends Parent { // static display() method =>hides display() in Parent class public static void display() { System.out.println('Child class:: static display()'); } //overrides print() in Parent class public void print() { System.out.println('Child class::Non-static print()'); } } public class Main { public static void main(String args( )) { Parent new_obj = new Child(); // static methods are call as per the reference type. Since reference type //Parent, this call will execute Parent class's display method new_obj.display(); // here the print () method of Child class is called new_obj.print(); } }
出力:
プログラムの出力から、次のように結論付けることができます。
- 静的メソッドの呼び出しは、常に参照のタイプに基づいて行われます。したがって、new_objを呼び出したとき。上記のプログラムのdisplay()は、new_obj参照のタイプがParentであるため、Parentクラスのdisplay()メソッドが呼び出されます。
- 一方、非静的メソッドは、メソッドが呼び出される参照オブジェクトの内容に基づいて呼び出されます。したがって、上記のプログラムでは、new_objの内容が子クラスのオブジェクトであるため、new_obj.print()メソッドは子クラスのprint()メソッドを呼び出します。
これは上記のプログラムの出力を説明しており、OOPシステムで静的メソッドを扱う際には次の点も覚えておく必要があります。
- 静的メソッドは非静的インスタンスメソッドを非表示にすることはできず、非静的インスタンスメソッドは静的メソッドをオーバーライドすることはできません。
- サブクラスの親クラスからメソッドをオーバーロードできますが、親クラスのメソッドをオーバーライドしたり非表示にしたりすることはなく、サブクラスの新しいメソッドです。
JavaでcompareTo()をオーバーライドする
インターフェイスjava.lang.Comparableは、「compareTo()」メソッドを提供します。これを使用して、Stringオブジェクトの辞書式順序、整数の番号順など、自然な順序でオブジェクトを並べ替えることができます。
ユーザー定義オブジェクトまたはコレクションで並べ替えを実装するには、compareTo()メソッドをオーバーライドして、コレクション要素またはユーザー定義オブジェクトを並べ替える必要があります。
では、compareTo()メソッドは何をするのでしょうか?
compareTo()メソッドは、現在のオブジェクトが渡されたオブジェクトよりも順番に大きく、現在のオブジェクトの負の値が渡されたオブジェクトよりも小さい場合、正の値を返す必要があります。両方のオブジェクトが等しい場合、compareTo()メソッドはゼロを返します。
注意すべきもう1つのポイントは、メソッドequals()とcompareTo()は互いに一貫して動作する必要があるということです。つまり、compareTo()メソッドが2つのオブジェクトが等しい(ゼロを返す)ことを返した場合、equals()メソッドからも同じ出力が得られるはずです。
compareTo()メソッドをオーバーライドするJavaプログラムを実装しましょう。このプログラムでは、nameとidの2つのプライベート変数を持つColorクラスを使用しています。 「id」を各色に関連付けました。compare()メソッドをオーバーライドして、idに従って色を配置します。
import java.util.*; //color class class Color implements Comparator, Comparable { private String name; private int id; Color() { } Color(String n, int id) { this.name = n; this.id = id; } public String getColorName() { return this.name; } public int getColorId() { return this.id; } // Overriding the compareTo method @Override public int compareTo(Color c) { return (this.name).compareTo(c.name); } // Overriding the compare method to sort the colors on id @Override public int compare(Color c, Color c1) { return c.id - c1.id; } } public class Main { public static void main(String args()) { // List of Colors List list = new ArrayList(); list.add(new Color('Red', 3)); list.add(new Color('Green', 2)); list.add(new Color('Blue', 5)); list.add(new Color('Orange', 4)); list.add(new Color('Yellow', 1)); Collections.sort(list); // Sorts the array list System.out.println('The list of colors:'); for(Color c: list) // print the sorted list of colors System.out.print(c.getColorName() + ', '); // Sort the array list using comparator Collections.sort(list, new Color()); System.out.println(' '); System.out.println('The sorted list of colors:'); for(Color c: list) // print the sorted list of colors as per id System.out.print(c.getColorId() + ':' + c.getColorName() + ' , '); }
出力:
上記の出力では、最初に色のリストを表示し、次にソートされた色のリストを表示します。プログラムでは、compareTo()メソッドとcompare()メソッドをオーバーライドしました。
JavaでtoString()メソッドをオーバーライドする
メソッド「toString()」は、Javaのオブジェクトの文字列表現を返します。ただし、ユーザー定義オブジェクトがある場合、このメソッドの動作は異なる場合があります。
例えば、次のプログラムを検討してください。
class Complex { private double r, i; public Complex(double r, double i) { this.r = r; this.i = i; } } public class Main { public static void main(String() args) { Complex c1 = new Complex(5, 20); //create complex class Object //print the contents of complex number System.out.println('Complex number contents: ' + c1); } }
出力:
このプログラムに示されているように、前に定義したComplexクラスオブジェクトを表示しています。ただし、表示される出力は内容ではなく、かなり不可解です。
出力には、クラス名Complex、「@」文字、オブジェクトのhashCodeが表示されます。これは、ObjectクラスのtoString()メソッドによって出力されるデフォルトの出力です。
適切な出力が必要な場合は、アプリケーションのtoString()メソッドをオーバーライドする必要があります。
次のJavaプログラムは、toString()メソッドをオーバーライドしてComplexオブジェクトのコンテンツを出力する方法を示しています。
class Complex { private double r, i; public Complex(double r, double i) { this.r = r; this.i = i; } //override toString () method to return String representation of complex number @Override public String toString() { return String.format(r + ' + i ' + i); } } public class Main { public static void main(String() args) { Complex c1 = new Complex(10, 15); System.out.println('Complex Number contents: ' + c1); } }
出力:
上記のプログラムは、toString()メソッドがオーバーライドされて、Complexオブジェクトのコンテンツを指定された形式(実数+虚数)で返すことを示しています。
一般に、print()またはprintln()のいずれかを使用してクラスオブジェクトを表示する場合は、適切な出力が得られるように、toString()メソッドをオーバーライドすることを常にお勧めします。
よくある質問
Q#1)== Javaの代わりに.equalsを使用するのはなぜですか?
回答: 「==」を使用して、int、char、booleanなどのプリミティブ型を比較します。equals()を使用して、オブジェクト(事前定義またはユーザー定義)を比較します。通常、equals()メソッドをオーバーライドして2つのオブジェクトを比較し、equals()の戻り値はオーバーライドされたコードによって異なります。
Q#2)hashCode()とequals()は何に使用されますか?
根本原因分析の例ソフトウェア開発
回答: Javaでは、equals()メソッドを使用して2つのオブジェクトの同等性を比較します。 hashCode()メソッドは、オブジェクトのhashCodeを返します。 equals()メソッドはほとんどのオブジェクトでそれらの同等性をテストするために使用されますが、hashCodeは主にHashTable、HashMap、HashSetなどのハッシュコレクションで使用されます。
Q#3)オーバーライドされたメソッドの引数リストを変更できますか?
回答: いいえ。メソッドをオーバーライドする場合、サブクラスでもメソッドのシグネチャまたはメソッドのプロトタイプを同じに保ちます。したがって、オーバーライドされたメソッドのパラメーターの数を変更することはできません。
Q#4)toString()をオーバーライドするのはなぜですか?
回答: toString()メソッドをオーバーライドすると、コードをあまり記述せずに、toString()メソッドがオーバーライドされたオブジェクトの値を返すことができます。これは、オブジェクトを出力するときにJavaコンパイラがtoString()メソッドを呼び出すためです。
Q#5)toString()メソッドをオーバーライドしないとどうなりますか?
回答: toString()メソッドをオーバーライドしないと、オブジェクトのプロパティや状態に関する情報を取得できません。オブジェクトの内部に実際に何があるかはわかりません。したがって、すべてのクラスはtoString()メソッドをオーバーライドする必要があります。
これは、toString()メソッドのデフォルトの実装では文字列表現が表示されますが、オブジェクトでデフォルトのtoString()実装を使用すると、オブジェクトのコンテンツが取得されないためです。
結論
このチュートリアルでは、いくつかの事前定義されたJavaメソッドのオーバーライドについて説明し、それらをオーバーライドする必要がある理由も確認しました。
オブジェクトを処理する場合、equals()、compareTo()、toString()などのメソッドのデフォルトの実装では正しい情報が得られない場合があります。したがって、オーバーライドします。