java pojo基类_一个较实用的Pojo(实体)基类

这篇博客介绍了如何实现一个实用的Java Pojo基类,重写了equals、hashCode和toString方法,以方便在泛型集合中进行对象比较和排序。作者强调了重写这些方法对于内容比较的重要性,特别是在处理集合和散列结构时的效率提升。文中还提供了一个具体的基类实现示例,并给出了测试用例来验证正确性和效率。
摘要由CSDN通过智能技术生成

转自:http://blog.csdn.net/CodingMouse/article/details/4064007

今天实现了一个较实用的Pojo(实体)基类

呵呵!也许你会觉得就单单重写了Object根类的equals、hashCode、toString这三个方法有什么意义?

实质上,如果你封装过泛型集合基类,并在泛型集合基类中玩过根据自定义属性排序的话,那么你会发现实现这样的一个Pojo基类很有必要!

先看看代码的实现:

packagecom.china.codingmouse.cmsdk4j.pojo;

importjava.io.Serializable;

importjava.lang.reflect.InvocationTargetException;

importjava.lang.reflect.Method;

importjava.util.List;

importjava.util.Vector;

/**

* BasePojo Pojo(实体)基类

* @author CodingMouse

* @version 1.0.0.1 2009-4-10

*/

publicclassBasePojoimplementsSerializable {

privatestaticfinallongserialVersionUID = -5520682886492533483L;// 版本序列号

/**

* 指示其他某个对象是否与此对象“相等”

*/

@Override

publicbooleanequals(Object obj) {

// 自身比较

if(obj ==this) {

returntrue;

}

// 类型相同

if(obj.getClass() ==this.getClass()) {

// 当前类反射方法组

Method[] thisMethodGroup = this.getClass().getMethods();

try{

// 遍历反射方法组并提取当前类属性的getter方法

for(Method method : thisMethodGroup) {

// 过滤与当前类属性无关的get方法

if(method.getName().startsWith("get")

&& !method.getName().equals("getClass")) {

// 将当前类属性的getter方法与比较类属性的getter方法值作比较

Method currentMethod = obj.getClass().getMethod(method.getName());

// 执行方法以获取返回值比较(关键点:注意参数不相同)

Object objReturnValue = currentMethod.invoke(obj);

Object thisReturnValue = method.invoke(this);

// 空值报异

if(objReturnValue ==null) {

System.err.println("异常信息:类"+ obj.getClass().getName()

+ "中的"+ currentMethod.getName() +"方法为null值!无法进行对象比较!");

}

if(thisReturnValue ==null) {

System.err.println("异常信息:类"+this.getClass().getName()

+ "中的"+ method.getName() +"方法为null值!无法进行对象比较!");

}

// 返回值不相等则返回逻辑假

if(!objReturnValue.equals(thisReturnValue)) {

returnfalse;

}

}

}

} catch(SecurityException ex) {

System.err.println("异常信息:参数错误,安全管理器检测到安全侵犯!/r/n"+ ex.getMessage());

} catch(NoSuchMethodException ex) {

System.err.println("异常信息:参数错误,无法找到某一特定的方法!/r/n"+ ex.getMessage());

} catch(IllegalArgumentException ex) {

System.err.println("异常信息:参数错误,向方法传递了一个不合法或不正确的参数!/r/n"+ ex.getMessage());

} catch(IllegalAccessException ex) {

System.err.println("异常信息:参数错误,对象定义无法访问,无法反射性地创建一个实例!/r/n"+ ex.getMessage());

} catch(InvocationTargetException ex) {

System.err.println("异常信息:参数错误,由调用方法或构造方法所抛出异常的经过检查的异常!/r/n"+ ex.getMessage());

}

}

// 通过不相等比较则返回逻辑真

returntrue;

}

/**

* 返回该对象的哈希码值

*/

@Override

publicinthashCode() {

// 生成简单的位运算hash散列码

String key = this.toString();

intprime = key.hashCode();

inthash = prime;

for(inti =0; i 

hash ^= (hash <>17) ^ key.charAt(i) *13131;

}

// 返回结果

return(hash % prime) *33;

}

/**

* 返回该对象的字符串表示(类似数组的toString方法输出结果)

*/

@Override

publicString toString() {

// 当前类反射方法组

Method[] methodGroup = this.getClass().getMethods();

// 保存内容

StringBuffer content = newStringBuffer("[");

// 保存属性的getter方法组

List getMethodGroup = newVector();

try{

// 遍历反射方法组并提取属性的getter方法

for(Method method : methodGroup) {

// 过滤与属性无关的get方法

if(method.getName().startsWith("get")

&& !method.getName().equals("getClass")) {

// 保存属性的getter方法

getMethodGroup.add(method);

}

}

// 处理仅包含属性的getter方法

for(inti =0; i 

// 执行get方法并拼接获取到的返回值(如果底层方法返回类型为 void,则该调用返回 null)

content.append(getMethodGroup.get(i).invoke(this)

+ ((i 

}

} catch(IllegalAccessException ex) {

System.err.println("异常信息:参数错误,对象定义无法访问,无法反射性地创建一个实例!/r/n"+ ex.getMessage());

} catch(IllegalArgumentException ex) {

System.err.println("异常信息:参数错误,向方法传递了一个不合法或不正确的参数!/r/n"+ ex.getMessage());

} catch(InvocationTargetException ex) {

System.err.println("异常信息:参数错误,由调用方法或构造方法所抛出异常的经过检查的异常!/r/n"+ ex.getMessage());

}

// 返回结果

returncontent.toString();

}

}

众所周知,String 、Math、还有包装类(如:Integer、Float、Double、Boolean等)都重写了Object的equals方法,这样才使得它们不再比较引用(某些地方也称为“句柄”,“句柄”一词貌似在Windows操作系统中经常使用,如“窗口句柄”),而是比较内容(值)相等。因为,Object的equals()方法比较的是地址值。

特别需要注意的是:

Java语言对equals()的要求如下,

对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

反射性:x.equals(x)必须返回是“true”。

类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

那么,又为什么要重写hashCode方法呢?网上的一些文章中是这样描述的:

我们应该先了解java判断两个对象是否相等的规则。

在Java的集合中,判断两个对象是否相等的规则是:

首先,判断两个对象的hashCode是否相等;

如果不相等,认为两个对象也不相等;

如果相等,则判断两个对象用equals运算是否相等;

如果不相等,认为两个对象也不相等;

如果相等,认为两个对象相等;

我们在equals方法中需要向下转型,效率很低,所以先判断hashCode方法可以提高效率。

一般来说,如果你要把一个类的对象放入集合中,那么通常要为其重写equals()方法,让它们比较地址值而不是内容值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。

另外,网上也有这样的一段描述:

关于在hibernate的pojo类中,重新equals()和hashcode()的问题:

1),重点是equals,重写hashCode只是技术要求(为了提高效率)

2),为什么要重写equals呢,因为在java的集合框架中,是通过equals来判断两个对象是否相等的

3),在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的。我们再来谈谈前面提到在向hashset集合中添加元素时,怎样判断对象是否相同的准则,前面说了两条,其实只要重写equals()这一条也可以。

但当hashset中元素比较多时,或者是重写的equals()方法比较复杂时,我们只用equals()方法进行比较判断,效率也会非常低,所以引入了hashcode()这个方法,只是为了提高效率,但是我觉得这是非常有必要的(所以我们在前面以两条准则来进行hashset的元素是否重复的判断)。

比如可以这样写:

public int hashCode(){

return 1;

} // 等价于hashcode无效

这样做的效果就是在比较哈希码的时候不能进行判断,因为每个对象返回的哈希码都是1,每次都必须要经过比较equals()方法后才能进行判断是否重复,这当然会引起效率的大大降低。

效率影响的体现可以在hashset、hashmap、hashtable、LinkedHashMap等带hash字样的集合中去测试,这里就不演示了。

至于为什么我要重写toString方法,有两点理由:

1、作为hashCode生成算法的一部分,与其内容直接相关,有更好的散列效果。

2、便于获取其子类更详细的内容描述,便于调试,而不是得到诸如“java.lang.Object@757aef”这样让人难以理解的文字内容。

我自己也编写了一个测例:

packagecom.china.codingmouse.cmsdk4j.example.pojo;

importjava.io.Serializable;

importjava.sql.Timestamp;

importcom.china.codingmouse.cmsdk4j.pojo.BasePojo;

/**

* UserPojo 用户信息实体类

* @author CodingMouse

* @version 1.0.0.1 2009-4-10

*/

publicclassUserPojoextendsBasePojoimplementsSerializable {

privatestaticfinallongserialVersionUID = -2214074259397104603L;// 版本序列号

privateintid;// 用户ID

privateString name;// 用户姓名

privatebooleansex;// 用户性别

privateintage;// 用户年龄

privateString address;// 用户住址

privateTimestamp regTime;// 用户注册时间

/**

* 默认构造器

*/

publicUserPojo() {

super();

}

/**

* 参数化构造器

* @param id       用户ID

* @param name     用户姓名

* @param sex      用户性别

* @param age      用户年龄

* @param address  用户住址

* @param regTime  用户注册时间

*/

publicUserPojo(intid, String name,booleansex,intage, String address, Timestamp regTime) {

super();

this.setId(id);

this.setName(name);

this.setSex(sex);

this.setAge(age);

this.setAddress(address);

this.setRegTime(regTime);

}

/**

* 用户ID取值方法

* @return 用户ID

*/

publicintgetId() {

returnid;

}

/**

* 用户ID赋值方法

* @param id 用户ID

*/

publicvoidsetId(intid) {

this.id = id;

}

/**

* 用户姓名取值方法

* @return 用户姓名

*/

publicString getName() {

returnname;

}

/**

* 用户姓名赋值方法

* @param name 用户姓名

*/

publicvoidsetName(String name) {

this.name = name;

}

/**

* 用户性别取值方法

* @return 用户性别

*/

publicbooleangetSex() {

returnsex;

}

/**

* 用户性别赋值方法

* @param sex 用户性别

*/

publicvoidsetSex(booleansex) {

this.sex = sex;

}

/**

* 用户年龄取值方法

* @return 用户年龄

*/

publicintgetAge() {

returnage;

}

/**

* 用户年龄赋值方法

* @param age 用户年龄

*/

publicvoidsetAge(intage) {

this.age = age;

}

/**

* 用户住址取值方法

* @return 用户住址

*/

publicString getAddress() {

returnaddress;

}

/**

* 用户住址赋值方法

* @param address 用户住址

*/

publicvoidsetAddress(String address) {

this.address = address;

}

/**

* 用户注册时间取值方法

* @return 用户注册时间

*/

publicTimestamp getRegTime() {

returnregTime;

}

/**

* 用户注册时间赋值方法

* @param regTime 用户注册时间

*/

publicvoidsetRegTime(Timestamp regTime) {

this.regTime = regTime;

}

}

packagecom.china.codingmouse.cmsdk4j.example.pojo.test;

importjava.sql.Timestamp;

importcom.china.codingmouse.cmsdk4j.example.pojo.UserPojo;

/**

* 用户信息实体类Equals与HashCode方法测试类

* @author CodingMouse

* @version 1.0.0.1 2009-4-10

*/

publicclassUserPojoEqualsAndHashCodeTest {

/**

* 测试类主方法

* @param args

*/

publicstaticvoidmain(String[] args) {

UserPojo up1 = newUserPojo(3,"邓超",true,25,"四川隆昌",newTimestamp(System.currentTimeMillis()));

UserPojo up2 = newUserPojo(3,"邓超",true,25,"四川隆昌",newTimestamp(System.currentTimeMillis()));

System.out.println("User1的内容:"+ up1);

System.out.println("User2的内容:"+ up2);

System.err.println("User1的散列码:"+ up1.hashCode());

System.err.println("User2的散列码:"+up2.hashCode());

System.out.println("测试User1与User2地址(==)相等:"+ (up1 == up2));

System.out.println("测试User1与User2内容(equals)相等:"+ up1.equals(up2));

UserPojo up3 = newUserPojo(6,"CodingMouse",false,22,"中华人民共和国四川成都",newTimestamp(System.currentTimeMillis()));

UserPojo up4 = newUserPojo(13,"Michael Jackson",false,53,"美利坚合众国纽约市唐人街",newTimestamp(System.currentTimeMillis()));

System.out.println("User3的内容:"+ up3);

System.out.println("User4的内容:"+ up4);

System.err.println("User3的散列码:"+up3.hashCode());

System.err.println("User4的散列码:"+up4.hashCode());

System.out.println("测试User3与User4地址(==)相等:"+ (up3 == up4));

System.out.println("测试User3与User4内容(equals)相等:"+ up3.equals(up4));

}

}

在Eclipse3.3控制台输出的最终的运行结果为:

User1的内容:[true, 25, 2009-04-10 18:39:54.557, 四川隆昌, 邓超, 3]

User2的内容:[true, 25, 2009-04-10 18:39:54.557, 四川隆昌, 邓超, 3]

User1的散列码:524379269

User2的散列码:524379269测试User1与User2地址(==)相等:false

测试User1与User2内容(equals)相等:true

User3的内容:[false, 22, 2009-04-10 18:39:54.563, 中华人民共和国四川成都, CodingMouse, 6]

User4的内容:[false, 53, 2009-04-10 18:39:54.563, 美利坚合众国纽约市唐人街, Michael Jackson, 13]

User3的散列码:-715569909

User4的散列码:956891732

测试User3与User4地址(==)相等:false

测试User3与User4内容(equals)相等:false

反正自我感觉挺良好的,如果您觉得有不妥的地方,还烦请帮忙指出为感!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值