锁定老帖子 主题:自己实现了一个较实用的Pojo(实体)基类
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-04-11
最后修改:2009-04-11
也许你会觉得就单单重写了Object根类的equals、hashCode、toString这三个方法有什么意义? 实质上,如果你封装过泛型集合基类,并在泛型集合基类中玩过根据自定义属性排序的话,那么你会发现实现这样的一个Pojo基类很有必要! package com.china.codingmouse.cmsdk4j.pojo; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.Vector; /** * BasePojo Pojo(实体)基类 * @author CodingMouse * @version 1.0.0.1 2009-4-10 */ public class BasePojo implements Serializable { private static final long serialVersionUID = -5520682886492533483L; // 版本序列号 /** * 指示其他某个对象是否与此对象“相等” */ @Override public boolean equals(Object obj) { // 自身比较 if (obj == this) { return true; } // 类型相同 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)) { return false; } } } } 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()); } } // 通过不相等比较则返回逻辑真 return true; } /** * 返回该对象的哈希码值 */ @Override public int hashCode() { // 生成简单的位运算hash散列码 String key = this.toString(); int prime = key.hashCode(); int hash = prime; for (int i = 0; i < key.length(); i++) { hash ^= (hash << 23 >> 17) ^ key.charAt(i) * 13131; } // 返回结果 return (hash % prime) * 33; } /** * 返回该对象的字符串表示(类似数组的toString方法输出结果) */ @Override public String toString() { // 当前类反射方法组 Method[] methodGroup = this.getClass().getMethods(); // 保存内容 StringBuffer content = new StringBuffer("["); // 保存属性的getter方法组 List<Method> getMethodGroup = new Vector<Method>(); try { // 遍历反射方法组并提取属性的getter方法 for (Method method : methodGroup) { // 过滤与属性无关的get方法 if (method.getName().startsWith("get") && !method.getName().equals("getClass")) { // 保存属性的getter方法 getMethodGroup.add(method); } } // 处理仅包含属性的getter方法 for (int i = 0; i < getMethodGroup.size(); i++) { // 执行get方法并拼接获取到的返回值(如果底层方法返回类型为 void,则该调用返回 null) content.append(getMethodGroup.get(i).invoke(this) + ((i < getMethodGroup.size() - 1) ? ",\u0020" : "]")); } } 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()); } // 返回结果 return content.toString(); } } 以下是此基类的一段测试代码: package com.china.codingmouse.cmsdk4j.example.pojo; import java.io.Serializable; import java.sql.Timestamp; import com.china.codingmouse.cmsdk4j.pojo.BasePojo; /** * UserPojo 用户信息实体类 * @author CodingMouse * @version 1.0.0.1 2009-4-10 */ public class UserPojo extends BasePojo implements Serializable { private static final long serialVersionUID = -2214074259397104603L; // 版本序列号 private int id; // 用户ID private String name; // 用户姓名 private boolean sex; // 用户性别 private int age; // 用户年龄 private String address; // 用户住址 private Timestamp regTime; // 用户注册时间 /** * 默认构造器 */ public UserPojo() { super(); } /** * 参数化构造器 * @param id 用户ID * @param name 用户姓名 * @param sex 用户性别 * @param age 用户年龄 * @param address 用户住址 * @param regTime 用户注册时间 */ public UserPojo(int id, String name, boolean sex, int age, 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 */ public int getId() { return id; } /** * 用户ID赋值方法 * @param id 用户ID */ public void setId(int id) { this.id = id; } /** * 用户姓名取值方法 * @return 用户姓名 */ public String getName() { return name; } /** * 用户姓名赋值方法 * @param name 用户姓名 */ public void setName(String name) { this.name = name; } /** * 用户性别取值方法 * @return 用户性别 */ public boolean getSex() { return sex; } /** * 用户性别赋值方法 * @param sex 用户性别 */ public void setSex(boolean sex) { this.sex = sex; } /** * 用户年龄取值方法 * @return 用户年龄 */ public int getAge() { return age; } /** * 用户年龄赋值方法 * @param age 用户年龄 */ public void setAge(int age) { this.age = age; } /** * 用户住址取值方法 * @return 用户住址 */ public String getAddress() { return address; } /** * 用户住址赋值方法 * @param address 用户住址 */ public void setAddress(String address) { this.address = address; } /** * 用户注册时间取值方法 * @return 用户注册时间 */ public Timestamp getRegTime() { return regTime; } /** * 用户注册时间赋值方法 * @param regTime 用户注册时间 */ public void setRegTime(Timestamp regTime) { this.regTime = regTime; } } package com.china.codingmouse.cmsdk4j.example.pojo.test; import java.sql.Timestamp; import com.china.codingmouse.cmsdk4j.example.pojo.UserPojo; /** * 用户信息实体类Equals与HashCode方法测试类 * @author CodingMouse * @version 1.0.0.1 2009-4-10 */ public class UserPojoEqualsAndHashCodeTest { /** * 测试类主方法 * @param args */ public static void main(String[] args) { UserPojo up1 = new UserPojo(3, "邓超", true, 25, "四川隆昌", new Timestamp(System.currentTimeMillis())); UserPojo up2 = new UserPojo(3, "邓超", true, 25, "四川隆昌", new Timestamp(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 = new UserPojo(6, "CodingMouse", false, 22, "中华人民共和国四川成都", new Timestamp(System.currentTimeMillis())); UserPojo up4 = new UserPojo(13, "Michael Jackson", false, 53, "美利坚合众国纽约市唐人街", new Timestamp(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)); } } 跑出来的结果: --------------------------------------------------------------------- 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 --------------------------------------------------------------------- 重写equals与hashCode方法是从所周知的事情,所以不多作说明。 至于为什么我要重写toString方法,有两点理由: 1、作为hashCode生成算法的一部分,与其内容直接相关,有更好的散列效果。 2、便于获取其子类更详细的内容描述,便于调试,而不是得到诸如“java.lang.Object@757aef”这样让人难以理解的文字内容。 正在写一个泛型BasePojoCollection(实体集合基类),想达到在基类中实现反射性地对子类自定义属性排序的功能。有了这样一个BasePojo为基础,就可以较容易地实现了!当然,还需要为这个BasePojo实现Comparable接口。 原来没有看到过别人做这样的尝试,如果你有更好的思路,还烦请指正为感! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-04-12
这反射用的也太不值钱了吧
|
|
返回顶楼 | |
发表时间:2009-04-12
支持造轮子 不过好多的ifelse
|
|
返回顶楼 | |
发表时间:2009-04-12
最后修改:2009-04-12
还是代码自动生成吧,然后设置一个eclipse的一个快捷键,自动把源文件作为输入,然后生成覆盖源文件,并自动刷新一下。
不过apache common已经提供了比较方便的方法可用。 |
|
返回顶楼 | |
发表时间:2009-04-12
请问楼主的与apache commons lang比较有何优势?
|
|
返回顶楼 | |
发表时间:2009-04-13
herowzz 写道 请问楼主的与apache commons lang比较有何优势? 谢谢各位的建议! 我只是一个初学者,也算是一个学生吧,只是凭空想象用来实现一些封装,以便于给伙伴使用,简化他们的代码编写。也许,我写的代码不地道。 对于apache commons lang,我没有去看过它的相关代码。也许各位的提醒得让我去注意一下了。 |
|
返回顶楼 | |
发表时间:2009-04-13
对于投隐藏贴的,不记名,怎么说也得给个理由吧,javaeye应该给这个功能
|
|
返回顶楼 | |
发表时间:2009-04-24
有必要搞的这么复杂吗!
反射是要降低性能的! 慎用! |
|
返回顶楼 | |
发表时间:2009-04-25
还是不错
|
|
返回顶楼 | |
发表时间:2009-04-25
不支持这样用,这么用反射没什么好处
我也投个隐藏 |
|
返回顶楼 | |