简体   繁体   English

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

[英]Effective Use of Java Reflection - is this a hack, or is this standard practice?

Hey, long time listener first time caller, and I'm asking a question related to Java reflection, and how easy it lends itself to apparently ugly coding. 嘿,长时间听众第一次打电话,我问一个与Java反射相关的问题,以及它是多么容易让自己看起来很丑陋的编码。 The following method attempts to take two similar objects (one object having all of the fields of the other object, and then some) and compare the two of them for equality. 下面的方法尝试获取两个相似的对象(一个对象具有另一个对象的所有字段,然后是一些对象),并将它们中的两个进行比较以获得相等性。 It will (allegedly) return true if the getters that the objects share are equal, and will return false if they are not equal. 如果对象共享的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;
}

This method does what I expect it to do in the unit tests, but it looks ugly, and feels wrong (I'm particularly not a fan of the nested 'if'). 这个方法做了我期望它在单元测试中做的事情,但它看起来很难看,并且感觉不对(我特别不喜欢嵌套'if'的粉丝)。 I was just hoping for some pointers on how to do this more effectively/efficiently. 我只是希望能有一些关于如何更有效/更有效地做到这一点的指示。 If I've broken some kind of posting rule, feel free to correct me, I am eager to learn, etc. 如果我违反了某种发布规则,请随时纠正我,我渴望学习等等。

For this particular task I would recommend implementing the equals method in the classes that will be compared, unless you don't have that option (for example, if you don't have the source code for the original class). 对于此特定任务,我建议在要比较的类中实现equals方法,除非您没有该选项(例如,如果您没有原始类的源代码)。 IDE's like IntelliJ provide support for the "equals" and "hashcode" methods creation (in IntelliJ, you provide the fields that will be compared and which fields can be null or not). 像IntelliJ这样的IDE提供了对“equals”和“hashcode”方法创建的支持(在IntelliJ中,您提供了将要比较的字段以及哪些字段可以为null或不为null)。 For this particular case, I would say go with these tools. 对于这个特殊情况,我会说使用这些工具。

There is one case where I think that an implementation using Reflection would be useful - in a unit test, if you want to throw an assertion error if the equality is no true, you can actually throw an assertion for the exact field that is failing, and not just a generic "object is not the same" assertion error - even in this case, I would perform an equals after my original validation just to be sure that the objects are the same, or at least that the equals method is implemented and working properly. 有一种情况我认为使用Reflection的实现会很有用 - 在单元测试中,如果你想在相等不成立时抛出一个断言错误,你实际上可以为失败的确切字段抛出一个断言,并且不只是一个通用的“对象不一样”的断言错误 - 即使在这种情况下,我会我的原始验证之后执行一个等于确保对象是相同的,或者至少是equals方法的实现和好好工作。

PS: If you want to get rid of all this coding check the Beans Common library; PS:如果你想摆脱所有这些编码检查Beans Common库; PS 2: Reflection is not bad, and it is used everywhere where you don't have an explicit code call - Spring configuration files, for example. PS 2:反射也不错,它可以在任何没有显式代码调用的地方使用 - 例如Spring配置文件。 Just don't abuse it. 只是不要滥用它。

As you are looking only for "properties" you could use commons beanutils and more precisely this class ... 因为你只关注“属性”,你可以使用commons beanutils ,更确切地说是这个类 ......

(I guess you cannot implement .equals because your objects don't share the same type...) (我猜你不能实现.equals,因为你的对象不共享相同的类型......)

I believe you're testing for unnecessary cases in your if statements, and can reduce them to this: 我相信你正在if语句中测试不必要的情况,并且可以将它们减少到这个:

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

Also, you're calling method.getName() 4 times, you could create a variable and then use it. 此外,您正在调用method.getName() 4次,您可以创建一个变量然后使用它。

Your return code is unnecessarily complicated. 您的返回代码不必要地复杂化。 The standard idiom for comparison of reference types is this: 用于比较参考类型的标准习语是:

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

This is much clearer and is pretty standard (Effective Java 2nd Edition, page 43). 这更加清晰,非常标准(Effective Java第2版,第43页)。


Update: 更新:

There was a confusion since earlier I had written return [idiom] . 从早些时候我写过return [idiom]就有一种混乱。 Yes, in this case a return would not be what the original poster want. 是的,在这种情况下, return不会是原始海报想要的。 He would want if ![idiom] return false; 他想要if ![idiom] return false; instead. 代替。 My point is that the [idiom] works, and it's much better. 我的观点是[idiom]有效,而且好多了。

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

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