对象的相等与比较
近一年多来,拜托轻量级容器的流行,POJO的使用率也随之上升。POJO的功能很简单,主要是用来在各模块之间传递数据。比如,有这么一个User类:
public class User
{
private int id;
private String name;
public void setId(int id)
{
this.id = id;
}
public int getId()
{
return this.id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
……
}
这个类的功能很简单,实现了POJO的基本功能,几乎所有的POJO都是这么一个模样。但是,仅仅这样的功能,我们在使用中经常会感到有些不方便。比如,我们可能会在业务逻辑中比较两个User对象是否为同一个User。就会有如下的代码:
if(user1.getId()==user2.getId())
{
……
}
对于这样的代码,看上去就感觉怪怪的,为什么?我们的目的是要两个User对象是否为同一个User,但判断语句却是在判断两个User对象的id是否相等,看到这个语句不能给人一种是在判断两个User是否为同一个User的感觉。如果改为下面的代码,是否给人感觉好一些呢?
If(user1.equals(user2))
{
……
}
这样一看代码就知道是在比较两个User对象是否为同一个User,代码的可读性就强多了。
这还不是需要改造代码的全部原因,如果在多个业务逻辑类里经常出现这样的判断,那么这就造成了一定的代码重复,是我们所忌讳的。
其实,equals方法继承自Object类,只要我们在POJO类里重写该方法就可以使用了。比如,在User类里改写如下:
public class User
{
……
public boolean equals(Object o)
{
//如果o为空,则返回false
if(o==null) return false;
//如果是同一个对象,则返回true
else if(o==this) return true;
//如果是User类的对象,且id相等,则返回true
else if(o instanceof User && ((User)o).getId()==this.id) return true;
else return false;
}
}
有了这个对象相等的方法,我们就可以在业务逻辑类中随时使用了,而不用使用取出id的有点dirty的代码了。
更多的时候,我们也会有这样的判断语句:
if(user1.getId==userId)
{
……
}
比如,我们在删除user的时候,要是不是删除了本人。这一个判断也不妨放在equals方法里头,我们在User类里重载equals方法,如下:
public boolean equals(int userId)
{
return this.id == userId;
}
呵呵,我们就可以这样判断:
if(user1.equals(userId))
{
……
}
这样,代码的可读性也要好一点。
有了相等,就有不相等。如果不相等的话,就要比较大小。例如,对容器里的对象进行排序或查找,就需要比较大小了。
Arrays类里涉及到对象比较的方法有两个:
Sort(Object[] os,Comparator comparator)
BinarySearch(Object[] os,Object o,Comparator comparator)
然后,Collections类里也有类似的两个方法,其他的容器类里也应该有类似的方法。所有的这些方法都要涉及到有关对象的比较,具体就是实现Comparator接口。
比如有这么一个Employee类:
public class Employee
{
private long id;
private String name;
private int servedYears;
public void setId(long id)
{
this.id = id;
}
public long getId()
{
return this.id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setServedYears(int servedYears)
{
this.servedYears = servedYears;
}
public int getServedYears()
{
return this.servedYears;
}
……
}
我们需要按员工的工作年数来排序,比如员工存在一个数组里:Employee[] emps = ……,则我们的排序代码为:
Arrays.sort(emps,new Comparator(){
Public int compare(Object o1,Object o2)
{
int sy1 = ((Employee)o1).getServedYears();
int sy2 = ((Employee)o2).getServedYears();
if(sy1>sy2) return 1;
else if(sy1<sy2) return –1;
else return 0;
}
});
示例代码1
public class User
{
private int id;
private String name;
public void setId(int id)
{
this.id = id;
}
public int getId()
{
return this.id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
……
}
这个类的功能很简单,实现了POJO的基本功能,几乎所有的POJO都是这么一个模样。但是,仅仅这样的功能,我们在使用中经常会感到有些不方便。比如,我们可能会在业务逻辑中比较两个User对象是否为同一个User。就会有如下的代码:
if(user1.getId()==user2.getId())
{
……
}
对于这样的代码,看上去就感觉怪怪的,为什么?我们的目的是要两个User对象是否为同一个User,但判断语句却是在判断两个User对象的id是否相等,看到这个语句不能给人一种是在判断两个User是否为同一个User的感觉。如果改为下面的代码,是否给人感觉好一些呢?
If(user1.equals(user2))
{
……
}
这样一看代码就知道是在比较两个User对象是否为同一个User,代码的可读性就强多了。
这还不是需要改造代码的全部原因,如果在多个业务逻辑类里经常出现这样的判断,那么这就造成了一定的代码重复,是我们所忌讳的。
其实,equals方法继承自Object类,只要我们在POJO类里重写该方法就可以使用了。比如,在User类里改写如下:
public class User
{
……
public boolean equals(Object o)
{
//如果o为空,则返回false
if(o==null) return false;
//如果是同一个对象,则返回true
else if(o==this) return true;
//如果是User类的对象,且id相等,则返回true
else if(o instanceof User && ((User)o).getId()==this.id) return true;
else return false;
}
}
有了这个对象相等的方法,我们就可以在业务逻辑类中随时使用了,而不用使用取出id的有点dirty的代码了。
更多的时候,我们也会有这样的判断语句:
if(user1.getId==userId)
{
……
}
比如,我们在删除user的时候,要是不是删除了本人。这一个判断也不妨放在equals方法里头,我们在User类里重载equals方法,如下:
public boolean equals(int userId)
{
return this.id == userId;
}
呵呵,我们就可以这样判断:
if(user1.equals(userId))
{
……
}
这样,代码的可读性也要好一点。
有了相等,就有不相等。如果不相等的话,就要比较大小。例如,对容器里的对象进行排序或查找,就需要比较大小了。
Arrays类里涉及到对象比较的方法有两个:
Sort(Object[] os,Comparator comparator)
BinarySearch(Object[] os,Object o,Comparator comparator)
然后,Collections类里也有类似的两个方法,其他的容器类里也应该有类似的方法。所有的这些方法都要涉及到有关对象的比较,具体就是实现Comparator接口。
比如有这么一个Employee类:
public class Employee
{
private long id;
private String name;
private int servedYears;
public void setId(long id)
{
this.id = id;
}
public long getId()
{
return this.id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void setServedYears(int servedYears)
{
this.servedYears = servedYears;
}
public int getServedYears()
{
return this.servedYears;
}
……
}
我们需要按员工的工作年数来排序,比如员工存在一个数组里:Employee[] emps = ……,则我们的排序代码为:
Arrays.sort(emps,new Comparator(){
Public int compare(Object o1,Object o2)
{
int sy1 = ((Employee)o1).getServedYears();
int sy2 = ((Employee)o2).getServedYears();
if(sy1>sy2) return 1;
else if(sy1<sy2) return –1;
else return 0;
}
});
示例代码1
sort方法里的匿名内部类需要实现compare方法。该方法有两个参数o1和o2,我们先是分别取出o1和o2的工作年数,然后,如果按照o1的工作年数大于o2的工作年数则返回一个正数,小于则返回一个负数,等于返回零的话,如上面的示例代码1所示,则数组按员工的年作年数的顺序排序。
否则,如果按照o1的工作年数小于o2的工作年数则返回一个正数,大于则返回一个负数,等于返回零的话,如上面的代码所示,则数组按员工的年作年数的倒序排序。如下面的代码所示:
Arrays.sort(emps,new Comparator(){
Public int compare(Object o1,Object o2)
{
int sy1 = ((Employee)o1).getServedYears();
int sy2 = ((Employee)o2).getServedYears();
if(sy1<sy2) return 1;
else if(sy1>sy2) return –1;
else return 0;
}
});
明白了排序的原理以后,我们可以看到上面示例代码1的代码还可以简化,如下所示:
Arrays.sort(emps,new Comparator(){
Public int compare(Object o1,Object o2)
{
return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();
}
});
在上面的代码里,返回的那个简单的算式结果其实就是示例代码1的那些代码的变形,也是o1的工作年数大于o2的工作年数则返回一个正数,小于则返回一个负数,等于则返回零。
关于方法binarySearch里的比较器和方法sort的一样适用。需要注意的是,在使用binarySearch方法的时候,先要将数组或者其他容器里的对象先排序,然后才能使用该方法来搜索某个对象。
好了,说到这里,该说的正题都已经说完了。就一句废话:对象的equals方法和比较器Comparator使用起来都蛮简单的,在实际的工作中,大家不妨用用看。