有效使用Java反射 - 这是一个黑客,还是这种标准做法?

时间:2010-02-22 16:05:57

标签: java reflection

嘿,长时间听众第一次打电话,我问一个与Java反射相关的问题,以及它有多容易使它看起来很难看。下面的方法尝试获取两个相似的对象(一个对象具有另一个对象的所有字段,然后是一些对象),并将它们中的两个进行比较以获得相等性。如果对象共享的getter相等,它将(据称)返回true,如果它们不相等则返回false。

public boolean validateArchive( Object record, Object arcRecord ) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
    log.debug( record.getClass().toString() );

    Object methodValue;
    Object arcMethodValue;

    for ( Method method : record.getClass().getMethods() )
    {
        if ( method.getTypeParameters().length == 0 && method.getName().startsWith( "get" ) && !method.getName().startsWith( "getClass" ) )
        {
            methodValue = method.invoke( record );
            arcMethodValue = arcRecord.getClass().getMethod( method.getName() ).invoke( arcRecord );

            log.debug( "Method name: " + method.getName() );
            log.debug( "Archive value: " + arcMethodValue );
            log.debug( "Object value: " + methodValue );

            if ( arcMethodValue != null && methodValue != null && !arcMethodValue.equals( methodValue ) )
            {
                return false;
            }
            else
            {
                if ( arcMethodValue == null && methodValue != null || methodValue == null && arcMethodValue != null )
                {
                    return false;
                }
            }
        }
    }

    return true;
}

这个方法做了我期望它在单元测试中做的事情,但它看起来很难看,并且感觉不对(我特别不喜欢嵌套的'if')。我只是希望能有一些关于如何更有效/更有效地做到这一点的指示。如果我违反了某种发布规则,请随时纠正我,我渴望学习等等。

4 个答案:

答案 0 :(得分:6)

对于此特定任务,我建议在要比较的类中实现equals方法,除非您没有该选项(例如,如果您没有原始类的源代码)。像IntelliJ这样的IDE提供了对“equals”和“hashcode”方法创建的支持(在IntelliJ中,您提供了将要比较的字段以及哪些字段可以为null或不为null)。对于这种特殊情况,我会说使用这些工具。

有一种情况我认为使用Reflection的实现会很有用 - 在单元测试中,如果你想在相等不为真的情况下抛出一个断言错误,你实际上可以为确切的字段抛出一个断言是失败的,而不仅仅是一个通用的“对象不一样”断言错误 - 即使在这种情况下,我会在原始验证后执行等于以确保对象是相同的,或者至少等于equals方法并且正常工作。

PS:如果你想摆脱所有这些编码,请检查Beans Common库; PS 2:反射也不错,它可以在任何没有显式代码调用的地方使用 - 例如Spring配置文件。只是不要滥用它。

答案 1 :(得分:2)

由于您只关注“属性”,因此可以使用commons beanutils,更准确地说this class ...

(我猜你不能实现.equals,因为你的对象不共享相同的类型......)

答案 2 :(得分:1)

我相信您正在对if语句中的不必要案例进行测试,并且可以将其缩减为:

if ( arcMethodValue == null ) {
    if ( methodValue != null) {
        return false;
    }
} else if ( !arcMethodValue.equals( methodValue ) ) {
    return false;
}

此外,您正在调用method.getName() 4次,您可以创建一个变量然后再使用它。

答案 3 :(得分:0)

您的返回代码不必要地复杂化。用于比较参考类型的标准惯用语是:

  (field1 == null) ? (field2 == null) : field1.equals(field2);

这更清晰,非常标准(Effective Java第2版,第43页)。


更新

自从我早些时候写过return [idiom]之后就出现了混乱。是的,在这种情况下,return不会是原始海报想要的。他想要if ![idiom] return false;代替。我的观点是[idiom]有效,而且效果更好。