利用反射比较两个对象是否相等

水深无声 2024-04-18 13:55 123阅读 0赞

java开发中,Junit做单测是必不可少的一环。然而对于单测结果的比较,仅仅通过Assert断言来比较远远不够。Assert只能比较基本类型,而对于对象是否相等,只能取出对象的值来,一一断言对比。这无疑给开发增加了很多无用的工作。下面简单介绍一个利用反射机制来实现对象比较的例子。话不多说,上代码。

  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. Map<String, Object> m = new HashMap();
  4. m.put("test","testvalue");
  5. TestEntity next1 = new TestEntity("testStr",222,m);
  6. TestEntity tn1 = new TestEntity("1212",999,m);
  7. tn1.setNext(next1);
  8. TestEntity next2 = new TestEntity("testStr",222,m);
  9. TestEntity tn2 = new TestEntity("1212",999,m);
  10. tn2.setNext(next2);
  11. Assert.assertEquals(tn1, tn2);
  12. }
  13. }

在这段代码里面,我创建了一个测试用的实体类,其中包含一个字符串属性,一个整型属性,一个Map属性以及一个实体类属性。通过上面代码可以看到,两个测试用的实体类的属性是一样的,然而使用断言,抛出了断言失败的异常。

  1. Exception in thread "main" java.lang.AssertionError: expected [com.mytest.Reflect.TestEntity@4b1210ee] but found [com.mytest.Reflect.TestEntity@4d7e1886]
  2. at org.testng.Assert.fail(Assert.java:94)
  3. at org.testng.Assert.failNotEquals(Assert.java:494)
  4. at org.testng.Assert.assertEquals(Assert.java:123)
  5. at org.testng.Assert.assertEquals(Assert.java:165)
  6. at com.mytest.Reflect.ReflectTest.main(ReflectTest.java:31)

接下来使用反射机制来实现对象的比较。上代码:

  1. private static boolean compareObject(Object o1, Object o2){
  2. // 记录比较结果
  3. boolean retFlag = true;
  4. // 首先判断需要比较的对象是否为null,一个为null,一个不是null时,返回不相等
  5. if((o1 == null && o2 != null)||(o1 != null && o2 == null)){
  6. return false;
  7. }
  8. // 都为null时,返回相等
  9. if(o1 ==null && o2==null){
  10. return true;
  11. }
  12. // +++++++++++++++++++++++都不为null时,继续比较+++++++++++++++++++++++++++++++
  13. // 首先比较两个对象的类型是否一致,类型不一致,直接返回不相等
  14. if(o1.getClass().isInstance(o2)){
  15. try {
  16. // 通过反射获取到需要比较的对象类
  17. Class clzz = Class.forName(o1.getClass().getName());
  18. // 获取类对应的属性对象
  19. Field[] fs = clzz.getDeclaredFields();
  20. // 依次比较各属性值
  21. for(Field ftemp : fs){
  22. // 获取属性名称
  23. String fieldName = ftemp.getName();
  24. // 组装属性对应的get方法
  25. String methodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
  26. // 通过get方法获取属性值
  27. Object v1 = clzz.getMethod(methodName).invoke(o1);
  28. Object v2 = clzz.getMethod(methodName).invoke(o2);
  29. // +++++++++++++++++++此处使用枚举出类型的方式,方法欠佳,仅供参考。+++++++++++++++++
  30. // 如果是基本类型或者是集合类型,则直接调用对象的equals方法
  31. if(v1 instanceof String || v1 instanceof Integer || v1 instanceof Short || v1 instanceof Long
  32. || v1 instanceof Byte || v1 instanceof Character || v1 instanceof Boolean
  33. || v1 instanceof Float || v1 instanceof Double || v1 instanceof Map){
  34. if(!compareValue(v1, v2)){
  35. retFlag = false;
  36. break;
  37. }
  38. }else{
  39. // 如果是对象类型,则继续递归调用本方法
  40. if(!compareObject(v1, v2)){
  41. retFlag = false;
  42. break;
  43. }
  44. }
  45. }
  46. } catch (ClassNotFoundException e) {
  47. System.out.println("fail to compare Objects !");
  48. retFlag = false;
  49. } catch (IllegalAccessException e) {
  50. System.out.println("fail to compare Objects !");
  51. retFlag = false;
  52. } catch (InvocationTargetException e) {
  53. System.out.println("fail to compare Objects !");
  54. retFlag = false;
  55. } catch (NoSuchMethodException e) {
  56. System.out.println("fail to compare Objects !");
  57. retFlag = false;
  58. }
  59. }else{
  60. retFlag = false;
  61. }
  62. return retFlag;
  63. }
  64. /**
  65. * 如果是基本类型或集合类,则直接用equals方法比较
  66. *
  67. * @param o1
  68. * @param o2
  69. * @return
  70. */
  71. private static boolean compareValue(Object o1, Object o2){
  72. if(o1 ==null || o2==null){
  73. return false;
  74. }
  75. // 集合类特性,实现了equals比较
  76. if(o1.equals(o2)){
  77. return true;
  78. }
  79. return false;
  80. }

下面是执行结果:
在这里插入图片描述
欢迎提问并指出更优方案。

发表评论

表情:
评论列表 (有 0 条评论,123人围观)

还没有评论,来说两句吧...

相关阅读

    相关 js比较对象是否相等

    > 前言:如何判断两个对象是否相等? 两个Object类型对象,即使拥有相同属性、相同值,当使用 == 或 === 进行比较时,也不认为他们相等。这就是因为他们是通过引用(内