【问题标题】:Compare fields of two unrelated objects比较两个不相关对象的字段
【发布时间】:2010-10-12 09:35:38
【问题描述】:

我有两个不同类的对象,它们共享一些具有相同名称和类型的字段。这两个对象彼此不相关。我无法创建接口或父类。

现在我想比较那些共享字段,据我所知,这应该可以使用反射。

这些是我为这种比较方法编写的步骤:

Field[] inputFields = input.getClass().getDeclaredFields();
for (Field field : inputFields ) {
    log.info(field.getName() + " : " + field.getType());
}

将有一个名为database 的对象与inputFields 的字段进行比较。

不幸的是,我不知道如何获取字段的值。你有什么提示吗?


好的,field.get(input) 我现在已经获得了价值,但也许我错了,这不是我需要的。 实际上,我想将此字段与另一个字段进行比较,因此我需要在此字段上调用 ​​equals 方法。但起初我必须将它转换为适当的类。 那么有没有像((field.getClass()) field).equals(...) 这样的东西可以工作?

【问题讨论】:

  • 为什么要使用反射?编写一个将两个对象作为参数并比较字段值的方法不是更容易吗(假设有getter)?
  • 是的,但是会很乏味。
  • 使用反射不是吗?当然,除非您知道这些字段的类型和/或名称会发生​​变化。
  • 如果编写与具体类型的比较太繁琐(如您所写),我建议您使用反射来生成代码中繁琐的部分。然后可以手动进一步微调生成的代码。这使您在运行时速度更快,并且可以自己查看比较逻辑。
  • @Neeme 哦,来吧,现在反射速度足够快,可以在运行时执行此操作。所有主要框架都在底层使用反射。

标签: java reflection comparison compare field


【解决方案1】:

我想你在找Field.get()

for (Field field : inputFields ) {
    log.info(field.getName() + " : " 
             + field.getType() + " = " 
             + field.get(input);
}

【讨论】:

    【解决方案2】:

    查看 Sun 的 Java 教程的 dedicated chapterThis page 以示例回答您的特定问题。

    【讨论】:

      【解决方案3】:

      这里有一个解决这个问题的方法,一个名为FieldHelper 的实用程序类,它有一个方法

      Map<String, Object[]> properties =
          FieldHelper.getCommonProperties(Object a, Object b)
      

      返回的地图以字段名作为键,两个字段值的数组作为值:

      public final class FieldHelper{
      
          private FieldHelper(){}
      
          private static final Map<Class<?>, Map<String, PropertyDescriptor>> cache =
              new HashMap<Class<?>, Map<String, PropertyDescriptor>>();
      
          /**
           * Return a Map of field names to {@link PropertyDescriptor} objects for a
           * given bean.
           */
          public static Map<String, PropertyDescriptor> getBeanProperties(final Object o){
      
              try{
                  final Class<?> clazz = o.getClass();
                  Map<String, PropertyDescriptor> descriptors;
                  if(cache.containsKey(clazz)){
                      descriptors = cache.get(clazz);
                  } else{
                      final BeanInfo beanInfo =
                          Introspector.getBeanInfo(clazz, Object.class);
                      descriptors = new TreeMap<String, PropertyDescriptor>();
                      for(final PropertyDescriptor pd : beanInfo.getPropertyDescriptors()){
                          descriptors.put(pd.getName(), pd);
                      }
                      cache.put(clazz,
                          new TreeMap<String, PropertyDescriptor>(descriptors));
                  }
                  final Map<String, PropertyDescriptor> beanProperties = descriptors;
                  return beanProperties;
      
              } catch(final IntrospectionException e){
                  throw new IllegalStateException("Can't get bean metadata", e);
              }
          }
      
          /**
           * Return a Map of all field names and their respective values that two
           * objects have in common. Warning: the field values can be of different
           * types.
           */
          public static Map<String, Object[]> getCommonProperties(final Object a,
              final Object b){
              final Map<String, PropertyDescriptor> aProps = getBeanProperties(a);
              final Map<String, PropertyDescriptor> bProps = getBeanProperties(b);
              final Set<String> aKeys = aProps.keySet();
              final Set<String> bKeys = bProps.keySet();
              aKeys.retainAll(bKeys);
              bKeys.retainAll(aKeys);
              final Map<String, Object[]> map = new TreeMap<String, Object[]>();
      
              for(final String propertyName : aKeys){
                  final Object aVal = getPropertyValue(a, aProps.get(propertyName));
                  final Object bVal = getPropertyValue(b, bProps.get(propertyName));
                  map.put(propertyName, new Object[] { aVal, bVal });
              }
              return map;
          }
      
          /**
           * Return the value of a bean property, given the bean and the {@link PropertyDescriptor}.
           */
          private static Object getPropertyValue(final Object a,
              final PropertyDescriptor propertyDescriptor){
              try{
                  return propertyDescriptor.getReadMethod().invoke(a);
              } catch(final IllegalArgumentException e){
                  throw new IllegalStateException("Bad method arguments", e);
              } catch(final IllegalAccessException e){
                  throw new IllegalStateException("Can't access method", e);
              } catch(final InvocationTargetException e){
                  throw new IllegalStateException("Invocation error", e);
              }
          }
      

      测试代码:

      public static void main(final String[] args){
          class Foo{
              private String abc = "abc";
              private String defy = "defy";
              private String ghi = "ghi";
              private String jkl = "jkl";
              // stripped getters and setters
              // they must be there for this to work
          }
          class Bar{
              private Boolean abc = true;
              private Integer def = 3;
              private String ghix = "ghix3";
              private Date jkl = new Date();
              // stripped getters and setters
              // they must be there for this to work
          }
          final Map<String, Object[]> properties =
              getCommonProperties(new Foo(), new Bar());
          for(final Entry<String, Object[]> entry : properties.entrySet()){
              System.out.println("Field: " + entry.getKey() + ", value a: "
                  + entry.getValue()[0] + ", value b: " + entry.getValue()[1]);
          }
      }
      

      输出:

      字段:abc,值a:abc,值b:真
      字段:jkl,值 a:jkl,值 b:Tue Oct 12 14:03:31 CEST 2010

      注意:此代码实际上并不读取字段,它遵循 java bean 约定并使用 getter 代替。重写它以使用字段很容易,但我建议不要这样做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-02-11
        • 1970-01-01
        • 2016-09-07
        • 2023-04-11
        • 1970-01-01
        • 1970-01-01
        • 2015-10-11
        相关资源
        最近更新 更多