How to define multiple equals() function for a class
I want to o开发者_JAVA技巧verride "public boolean equals(Object obj)" function, for name and age, in my class named MyObject whose structure is given below
public class MyObject{
private String name;
private int age;
}
How can i ?
@balusC :
What about this ?
vo = new MyObject() {
public boolean equals(Object obj) {
return ((MyObject)obj).name().equals(this.getName());
}
vo = new MyObject() {
public boolean equals(Object obj) {
return ((MyObject)obj).age() == (this.getAge());
Your question is a bit vague, but if the sole purpose is to have different sorting algorithms depending on what property you'd like to use, then rather use a Comparator
.
public class Person {
private String name;
private int age;
public static Comparator COMPARE_BY_NAME = new Comparator<Person>() {
public int compare(Person one, Person other) {
return one.name.compareTo(other.name);
}
}
public static Comparator COMPARE_BY_AGE = new Comparator<Person>() {
public int compare(Person one, Person other) {
return one.age > other.age ? 1
: one.age < other.age ? -1
: 0; // Maybe compare by name here? I.e. if same age, then order by name instead.
}
}
// Add/generate getters/setters/equals()/hashCode()/toString()
}
which you can use as follows:
List<Person> persons = createItSomehow();
Collections.sort(persons, Person.COMPARE_BY_NAME);
System.out.println(persons); // Ordered by name.
Collections.sort(persons, Person.COMPARE_BY_AGE);
System.out.println(persons); // Ordered by age.
As to the actual equals()
implementation, I'd rather let it return true when the both Person
objects are techically or naturally identical. You can use either a DB-generated PK for this to compare on technical identity:
public class Person {
private Long id;
public boolean equals(Object object) {
return (object instanceof Person) && (id != null)
? id.equals(((Person) object).id)
: (object == this);
}
}
or just compare every property to compare on natural identity:
public class Person {
private String name;
private int age;
public boolean equals(Object object) {
// Basic checks.
if (object == this) return true;
if (object == null || getClass() != object.getClass()) return false;
// Property checks.
Person other = (Person) object;
if (name == null ? other.name != null : !name.equals(other.name)) return false;
if (age != other.age) return false;
// All passed.
return true;
}
}
Don't forget to override hashCode()
as well when you override equals()
.
See also:
- Object ordering
- Sorting an ArrayList of objects
- Overriding
equals()
andhashCode()
I'm not exactly sure what you're aiming at with this. The general expectation of equals() is that it returns false
for null
and objects of other classes and performs value equality on the relevant fields of the class in question.
While you can certainly handle String
and Integer
in the following way:
public boolean equals(Object o) {
if (o == null) return false;
if (o instanceof String) return name.equals(o);
if (o instanceof Integer) return ((Integer)o) == age;
...
}
this breaks the contract for equals
so you can't do it (except not without things going wrong in very weird ways).
equals
is an equivalence relation, so it has to be reflexive, symmetric and transitive. The symmetric part here is key, since if a.equals(b)
then b.equals(a)
. Both String
and Integer
won't do that for you.
If you want just helper functions that check whether the name or the age is equals to a given name/age, then you can do that without using equals()
:
public boolean equalsName(String name) { return name.equals(this.name); }
public boolean equalsAge(int age) { return age == this.age; }
Just keep it short and simple (aka KISS principle): write setters and getters. Something like in the following example:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
And then in the method you need to do the check you can write:
Person person = new Person();
if(person.getName().equals("Something")) doThis();
if(person.getAge() == 1337) doThat();
Not sure what you mean by "multiple equals()". If you want compare both your fields, you just need to override the equals method like this,
public boolean equals( Object o )
{
if ( o != null && o instanceof MyObject )
{
MyObject m = (MyObject) o;
if (this.name == null)
return false;
return this.name.eqauls(m.name) && this.age == m.age;
}
return false;
}
/// Compute a hash code for the pair.
public int hashCode()
{
int code = name == null ? 0 : name.hashCode();
return code ^ age;
}
It's a good practice to change hashCode whenever you change equals so HashMap works efficiently with your object.
if you do want to override equals, it should look something like this:
static private <T> boolean checkEquals(T t1, T t2)
{
return (t1 == null) ? (t2 == null) : t1.equals(t2);
}
@Override public boolean equals (Object o)
{
if (o instanceof MyObject)
{
MyObject obj = (MyObject)o;
return checkEquals(this.name, obj.getName())
&& this.age == o.getAge();
}
else
return false;
}
@Override public int hashCode()
{
// implement hashCode
}
You need to override both hashCode() and equals() or neither. And you also should make sure your class is final
, otherwise there are potential pitfalls with equals.
public class MyObject {
private String name;
private int age;
@Override
public boolean equals(Object o){
if(o instanceof MyObject){
MyObject otherObject = (MyObject)o;
if(name == null){
return otherObject.name == null && otherObject.age == age;
} else {
return name.equals(otherObject.name) && otherObject.age == age;
}
} else {
return false;
}
}
// When we overriding equals it is a good practice to override hashCode
// for consistecy
@Override
public int hashCode(){
int nameCode = (name == null) ? 0 : name.hashCode();
// See Item 9 in book Effective Java 2nd Edition
return 31 * nameCode + age;
}
}
精彩评论