Sa post na ito ay ilalarawan ko ang aking pag-unawa sa mga pamamaraan Переопределение
Apache Commons предоставляет два замечательных вспомогательных класса для вызова методов
hashCode()
at equals()
. Gusto kong pag-usapan ang kanilang default na pagpapatupad, pati na rin kung paano i-override ang mga ito nang tama. Magsusulat din ako tungkol sa pagpapatupad ng mga pamamaraang ito gamit ang mga klase ng helper ng Apache Common package. Mga nilalaman ng post na ito:
- Paggamit
hashCode()
ng atequals()
. - I-override ang default na gawi.
- Ino-override
hashCode()
atequals()
ginagamit ang Apache Commons Lang. - Isang bagay na mahalagang tandaan.
- Espesyal na Atensyon Kapag Gumagamit ng ORM.
hashCode()
Ang at mga pamamaraan equals()
ay tinukoy sa class Object
, na siyang parent class para sa java objects. Samakatuwid, ang lahat ng java object ay nagmamana ng default na pagpapatupad mula sa mga pamamaraang ito.
Paggamit ng hashCode() at equals()
Ang pamamaraanhashCode()
ay ginagamit upang makakuha ng isang natatanging integer na numero para sa isang ibinigay na bagay. Kapag ang isang bagay ay kailangang maimbak bilang isang istraktura ng data sa isang hash table (tinatawag ding bucket), ang numerong ito ay ginagamit upang matukoy ang lokasyon nito sa talahanayang iyon. Bilang default, ibinabalik ng pamamaraan hashCode()
para sa isang bagay ang bilang ng lokasyon ng memorya kung saan nakaimbak ang bagay. Ang pamamaraan equals()
, gaya ng ipinahihiwatig ng pangalan nito, ay ginagamit upang suriin lamang ang pagkakapantay-pantay ng dalawang bagay. Ang default na pagpapatupad ng pamamaraang ito ay sinusuri lamang ang mga sanggunian ng dalawang bagay upang makita kung ang mga ito ay katumbas.
Ino-override ang default na gawi
Gumagana nang maayos ang lahat hangga't hindi mo i-override ang alinman sa mga pamamaraang ito sa iyong mga klase. Ngunit kung minsan ang mga application ay kailangang baguhin ang default na pag-uugali ng ilang mga bagay. Kumuha tayo ng isang halimbawa kung saan mayroon kangEmployee
. Isulat natin ang pinakamababang posibleng istraktura ng naturang klase.
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;
}
}
Ang klase na inilarawan sa itaas Employee
ay may ilang pangunahing katangian at paraan ng accessor. Ngayon tingnan natin ang isang simpleng sitwasyon kung saan kailangan nating paghambingin ang dalawang bagay ng klase 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));
}
}
Hindi kinakailangan ng isang clairvoyant na hulaan na ang pamamaraan sa itaas ay magbabalik ng "false". Ngunit ito ba ay talagang tama, dahil ang dalawang bagay na ito ay pareho? Sa real time na aplikasyon, ang pamamaraan ay dapat bumalik ng totoo. Upang makamit ang tamang pag-uugali, kailangan nating i-override ang pamamaraan equals()
, gaya ng ginawa sa ibaba:
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());
}
Idagdag ang paraang ito sa iyong klase Employee
at ang equivalence check ay magbabalik ng “true”. Gayunpaman, nagawa ba natin ang lahat? Hindi pa. Subukan natin ang aming binagong klase sa isa pang paraan.
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)
распечатывает два an object. Если оба an object были эквивалентны, а в Set
содержатся только уникальные an objectы, то внутри HashSet
должен быть только один экземпляр, т.е. оба an object ссылаются на одинаковые экземпляры класса Employee
. What же мы упустor? Мы упустor второй важный метод hashCode()
. Как сказано в documentации java, если вы переопределяете метод equals()
, то вы обязаны переопределить метод hashCode()
. Итак, давайте добавим ещё один метод в наш класс Employee
.
@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
Мы добавor один раз этот метод в наш класс, и на печать будет выведен только один an object, и, таким образом, проверка эквивалентности е1 и е2 показала true.
Переопределение hashCode()
и equals()
, используя Apache Commons Lang
Apache Commons предоставляет два замечательных вспомогательных класса для вызова методов hashCode()
и 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();
}
}
С другой стороны, если вы используете один из редакторов codeа, они также должны быть способны вызывать некоторые хорошие структуры для вас. Например, если в Eclipse IDE кликнуть правой клавишей на class >> sourse > Generating hashCode() and equals() … будет сгенерирована очень хорошая реализация для вас. То, что важно помнить.
- Всегда используйте те же атрибуты an object для вызова и
hashCode()
иequals()
. Как раз в нашем случае, мы использовалиemployee id
. - Метод
equals()
должен быть устойчивым (если an object не изменялся, метод должен возвращать то же самое meaning). - Всякий раз, когда
a.equals(b)
, тоa.hashCode()
должно быть таким же, Howb.hashCode()
. - Если вы переопределor один метод, то обязательно должны переопределить второй.
Особое Внимание При Использовании ORM
Если вы имеете дело с ORM (ru.wikipedia.org/wiki/ORM), то всегда используйте геттеры и никогда не используйте вhashCode()
и equals()
ссылки на поля. Это потому, что в ORM, время от времени поля загружаются при помощи отложенной загрузки (lazy load) и не доступны, пока не вызваны их геттеры. Например, в нашем классе Employee
, мы используем e1.id == e2.id
. Вполне возможно, что поля i
d загружены с помощью отложенной загрузки. Одно из полей может быть равно 0 or null и мы получим некорректное поведение. Но, если используется e1.getId() == e2.getId()
, мы можем быть уверены, даже если поля были загружены с помощью отложенной загрузки; вызов геттера первым заполнит поле. Это всё, что я знаю о методах hashCode()
и equals()
. Надеюсь, что это где-нибудь кому-нибудь поможет. Удачи в учебе!! p.s. Это моя первая попытка перевода. Постаралась передать всё How можно ближе к тому, что хотел сказать автор. Если есть замечания, пожалуйста, напишите в комментариях. Строго не судите :-))) Oригинал статьи
GO TO FULL VERSION