この投稿では、メソッドApache Commons Lang のオーバーライド
hashCode()
とについての私の理解を概説しますequals()
。それらのデフォルトの実装と、それらを正しくオーバーライドする方法について話したいと思います。Apache Common パッケージのヘルパー クラスを使用したこれらのメソッドの実装についても書きます。 この投稿の内容:
hashCode()
と を使用しますequals()
。- デフォルトの動作をオーバーライドします。
- Apache Commons Lang をオーバーライドし
hashCode()
てequals()
使用します。 - 覚えておくべき重要なこと。
- ORM を使用する場合の特別な注意。
hashCode()
およびメソッドは、Java オブジェクトの親クラスである classequals()
に定義されています。Object
したがって、すべての Java オブジェクトは、これらのメソッドからデフォルトの実装を継承します。
hashCode()とequals()の使用
このメソッドは、hashCode()
特定のオブジェクトの一意の整数を取得するために使用されます。オブジェクトをデータ構造としてハッシュ テーブル (バケットとも呼ばれます) に保存する必要がある場合、この番号を使用してテーブル内のオブジェクトの位置が決定されます。デフォルトでは、オブジェクトのメソッドは、hashCode()
オブジェクトが保存されているメモリ位置の番号を返します。メソッド はequals()
、その名前が示すように、2 つのオブジェクトの同等性を単純にチェックするために使用されます。このメソッドのデフォルトの実装では、2 つのオブジェクトの参照を単純にチェックして、それらが同等であるかどうかを確認します。
デフォルトの動作をオーバーライドする
クラス内でこれらのメソッドをオーバーライドしない限り、すべてが正常に動作します。ただし、アプリケーションで一部のオブジェクトのデフォルトの動作を変更する必要がある場合があります。がある場合の例を見てみましょうEmployee
。このようなクラスの可能な最小限の構造を書いてみましょう。
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
上で説明したクラスには、Employee
いくつかの基本的な属性とアクセサー メソッドがあります。次に、 クラス の 2 つのオブジェクトを比較する必要がある簡単な状況を見てみましょうEmployee
。
public class EqualsTest {
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Печатает false в консоли
System.out.println(e1.equals(e2));
}
}
上記のメソッドが「false」を返すことを推測するのに千里眼は必要ありません。しかし、これら 2 つのオブジェクトが同じであるとすると、これは実際に正しいのでしょうか? リアルタイム アプリケーションでは、メソッドは true を返す必要があります。equals()
正しい動作を実現するには、以下のように メソッドをオーバーライドする必要があります。
public boolean equals(Object o) {
if(o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (getClass() != o.getClass())
{
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
このメソッドをクラスに追加するEmployee
と、等価性チェックで「true」が返されます。しかし、私たちはすべてをやり遂げたでしょうか?まだ。変更したクラスを別の方法でテストしてみましょう。
import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
public static void main(String[] args)
{
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Печатает 'true'
System.out.println(e1.equals(e2));
Set employees = new HashSet();
employees.add(e1);
employees.add(e2);
//Печатает два an object
System.out.println(employees);
}
}
このコマンドはSystem.out.println(employee)
2 つのオブジェクトを出力します。両方のオブジェクトが同等で、Set
一意のオブジェクトのみが含まれている場合、HashSet
内部にはインスタンスが 1 つだけ存在するはずです。どちらのオブジェクトも、クラスの同じインスタンスを参照しますEmployee
。私たちは何を見逃してしまったのでしょうか?2 番目の重要なメソッドを見逃していましたhashCode()
。Java ドキュメントに記載されているように、メソッドをオーバーライドする場合はequals()
、メソッドをオーバーライドする必要がありますhashCode()
。そこで、クラスに別のメソッドを追加しましょうEmployee
。
@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
このメソッドをクラスに一度追加すると、オブジェクトが 1 つだけ出力されるため、e1 と e2 の等価性をチェックすると true であることがわかりました。
Apache Commons Lang のオーバーライドhashCode()
と使用equals()
hashCode()
Apache Commons は、メソッドと を呼び出すための 2 つの優れたヘルパー クラスを提供しますequals()
。以下に使用法を示します。
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public int hashCode()
{
final int PRIME = 31;
return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
toHashCode();
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (o == this)
return true;
if (o.getClass() != getClass())
return false;
Employee e = (Employee) o;
return new EqualsBuilder().
append(getId(), e.getId()).
isEquals();
}
}
一方、コード エディターのいずれかを使用すると、いくつかの優れた構造を呼び出すこともできるはずです。たとえば、Eclipse IDE で [クラス] >> [ソース] > [ハッシュコード() および等しい() の生成] を右クリックすると、非常に優れた実装が生成されます。 覚えておくべき重要なこと。
hashCode()
と、 の両方を呼び出すには、常に同じオブジェクト属性を使用してくださいequals()
。私たちの場合だけ、 を使用しましたemployee id
。- メソッドは
equals()
永続的である必要があります (オブジェクトが変更されていない場合、メソッドは同じ値を返す必要があります)。 - いつでも
a.equals(b)
、 then は とa.hashCode()
同じでなければなりませんb.hashCode()
。 - 1 つのメソッドをオーバーライドする場合は、2 番目のメソッドもオーバーライドする必要があります。
ORM 使用時の特別な注意
ORM (ru.wikipedia.org/wiki/ORM) を扱う場合は、常にゲッターを使用し、フィールド参照は決して使用しないでくださいhashCode()
。equals()
これは、ORM では、フィールドが遅延ロードを使用してロードされ、ゲッターが呼び出されるまでアクセスできない場合があるためです。たとえば、私たちのクラスではEmployee
を使用しますe1.id == e2.id
。d フィールドが遅延読み込みを使用して読み込まれる可能性は十分にありますi
。フィールドの 1 つが 0 または null である可能性があり、誤った動作が発生します。ただし、 を使用するとe1.getId() == e2.getId()
、フィールドが遅延読み込みを使用して読み込まれた場合でも確実に確認できます。getter を呼び出すと、最初にフィールドに値が設定されます。hashCode()
とメソッドについて私が知っているのはこれだけですequals()
。これがどこかの誰かの役に立てば幸いです。勉強頑張ってください!! ps これは私にとって初めての翻訳の試みです。作者の言いたいことにできるだけ近いものを伝えるように努めました。ご意見がございましたら、コメント欄にご記入ください。厳密に判断しないでください:-))) 元の記事
GO TO FULL VERSION