简体   繁体   English

比较两个不相关对象的字段

[英]Compare fields of two unrelated objects

I've got two objects of different classes that share some fields with the same name and type. 我有两个不同类的对象,它们共享一些具有相同名称和类型的字段。 These two objects are not related to each other. 这两个对象彼此不相关。 There's no possibility for me to create an interface or a parent class. 我无法创建接口或父类。

Now I want to compare those shared fields and as far as I know this should be possible using reflection. 现在,我想比较那些共享字段,据我所知,应该可以使用反射来实现。

These are the steps I've written for such a compare method: 这些是我为比较方法编写的步骤:

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

There will be an object called database to which's fields the inputFields are compared. 将有一个名为database的对象,与inputFields的字段进行比较。

Unfortunately I don't know how to get the value of my fields. 不幸的是,我不知道如何获得我的领域的价值。 Do you have some hints for me? 你对我有什么提示吗?


Ok, with field.get(input) I've got the value now, but maybe I was wrong and that's not what I need. 好的,有了field.get(input)我现在有了值,但是也许我错了,那不是我所需要的。 Actually, I want to compare this field with another one, so I need to call the equals method on this field. 实际上,我想将此字段与另一个字段进行比较,因此我需要在该字段上调用equals方法。 But at first I've got to cast it to it's appropriate class. 但首先,我必须将其转换为适当的类。 So is there something like ((field.getClass()) field).equals(...) that would work? 那么是否有像((field.getClass()) field).equals(...)这样的东西可以工作?

I think you're looking for Field.get() : 我认为您正在寻找Field.get()

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

Check dedicated chapter of Sun's Java tutorial. 查看Sun Java教程的专用章节 This page answers your particular question with example. 此页面以示例回答您的特定问题。

Here is a Solution to this problem, a utility class called FieldHelper that has a method 这是此问题的解决方案,它是一个名为FieldHelper的实用程序类,它具有一个方法

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

The returned map has the field name as key and an array of the two field values as value: 返回的映射将字段名称作为键,并将两个字段值的数组作为值:

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);
        }
    }

Test Code: 测试代码:

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]);
    }
}

Output: 输出:

Field: abc, value a: abc, value b: true 字段:abc,值a:abc,值b:true
Field: jkl, value a: jkl, value b: Tue Oct 12 14:03:31 CEST 2010 栏位:jkl,值a:jkl,值b:2010年10月12日星期二14:03:31

Note: this code doesn't actually read the fields, it follows the java bean convention and uses the getters instead. 注意:此代码实际上并不读取字段,而是遵循Java bean约定,而是使用getter。 It would be easy to rewrite it to use fields, but I would advise against it. 重写它以使用字段会很容易,但是我建议不要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM