如果我删除extends Comparable< Version>版本的一部分,我得到预期的行为 – ==给出与equals相同的结果.
我在其他地方读过Groovy委托==到equals(),除非该类实现了Comparable,在这种情况下它委托compareto.但是,我发现两个都声明版本的两个实例相等而且==检查失败的情况.
我创建了一个演示此行为的SSCCE here.
完整代码也在下面提供:
// Interface extending Comparableinterface Super extends Comparable<Super> { int getValue()}class SubA implements Super { int getValue() { 1 } int compareto(Super that) { this.value <=> that.value } boolean equals(Object o) { if (o == null) return false if (!(o instanceof Super)) return false this.value == o.value }}class SubB implements Super { int getValue() { 1 } int compareto(Super that) { this.value <=> that.value } boolean equals(Object o) { if (o == null) return false if (!(o instanceof Super)) return false this.value == o.value }}// Interface not extending Comparableinterface AnotherSuper { int getValue()}class AnotherSubA implements AnotherSuper { int getValue() { 1 } boolean equals(Object o) { if (o == null) return false if (!(o instanceof AnotherSuper)) return false this.value == o.value }}class AnotherSubB implements AnotherSuper { int getValue() { 1 } boolean equals(Object o) { if (o == null) return false if (!(o instanceof AnotherSuper)) return false this.value == o.value }}// Check with comparable versionsdef a = new SubA()def b = new SubB()println "Comparable versions equality check: ${a == b}"println "Explicit comparable equals check: ${a.equals(b)}"println "Explicit comparable compareto check: ${a.compareto(b)}"// Check with non-comparable versionsdef anotherA = new AnotherSubA()def anotherB = new AnotherSubB()println "Non-comparable versions equality check: ${anotherA == anotherB}"println "Explicit non-comparable equals check: ${anotherA.equals(anotherB)}"
我得到的回报是:
Comparable versions equality check: falseExplicit comparable equals check: trueExplicit comparable compareto check: 0Non-comparable versions equality check: trueExplicit non-comparable equals check: true
编辑
我想我明白为什么现在会发生这种情况,这要归功于Poundex与下面链接的@L_419_1@.
从Groovy的DefaultTypeTransformation class开始,它用于处理相等/比较检查,我假设在评估x == y形式的语句时首先调用compareEqual方法:
public static boolean compareEqual(Object left,Object right) { if (left == right) return true; if (left == null || right == null) return false; if (left instanceof Comparable) { return comparetoWithEqualityCheck(left,right,true) == 0; } // handle arrays on both sIDes as special case for efficIEncy Class leftClass = left.getClass(); Class rightClass = right.getClass(); if (leftClass.isArray() && rightClass.isArray()) { return compareArrayEqual(left,right); } if (leftClass.isArray() && leftClass.getComponentType().isPrimitive()) { left = primitiveArrayToList(left); } if (rightClass.isArray() && rightClass.getComponentType().isPrimitive()) { right = primitiveArrayToList(right); } if (left instanceof Object[] && right instanceof List) { return DefaultGroovyMethods.equals((Object[]) left,(List) right); } if (left instanceof List && right instanceof Object[]) { return DefaultGroovyMethods.equals((List) left,(Object[]) right); } if (left instanceof List && right instanceof List) { return DefaultGroovyMethods.equals((List) left,(List) right); } if (left instanceof Map.Entry && right instanceof Map.Entry) { Object k1 = ((Map.Entry)left).getKey(); Object k2 = ((Map.Entry)right).getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = ((Map.Entry)left).getValue(); Object v2 = ((Map.Entry)right).getValue(); if (v1 == v2 || (v1 != null && DefaultTypetransformation.compareEqual(v1,v2))) return true; } return false; } return ((Boolean) InvokerHelper.invokeMethod(left,"equals",right)).booleanValue();}
请注意,如果表达式的LHS是Comparable的实例,就像我提供的示例中那样,则将比较委托给comparetoWithEqualityCheck:
private static int comparetoWithEqualityCheck(Object left,Object right,boolean equalityCheckOnly) { if (left == right) { return 0; } if (left == null) { return -1; } else if (right == null) { return 1; } if (left instanceof Comparable) { if (left instanceof Number) { if (right instanceof Character || right instanceof Number) { return DefaultGroovyMethods.compareto((Number) left,castToNumber(right)); } if (isValIDCharacterString(right)) { return DefaultGroovyMethods.compareto((Number) left,ShortTypeHandling.casttochar(right)); } } else if (left instanceof Character) { if (isValIDCharacterString(right)) { return DefaultGroovyMethods.compareto((Character)left,ShortTypeHandling.casttochar(right)); } if (right instanceof Number) { return DefaultGroovyMethods.compareto((Character)left,(Number)right); } } else if (right instanceof Number) { if (isValIDCharacterString(left)) { return DefaultGroovyMethods.compareto(ShortTypeHandling.casttochar(left),(Number) right); } } else if (left instanceof String && right instanceof Character) { return ((String) left).compareto(right.toString()); } else if (left instanceof String && right instanceof GString) { return ((String) left).compareto(right.toString()); } if (!equalityCheckOnly || left.getClass().isAssignableFrom(right.getClass()) || (right.getClass() != Object.class && right.getClass().isAssignableFrom(left.getClass())) //GROOVY-4046 || (left instanceof GString && right instanceof String)) { Comparable comparable = (Comparable) left; return comparable.compareto(right); } } if (equalityCheckOnly) { return -1; // anything other than 0 } throw new GroovyRuntimeException( messageformat.format("Cannot compare {0} with value ''{1}'' and {2} with value ''{3}''",left.getClass().getname(),left,right.getClass().getname(),right));}
在底部附近,该方法有一个块,它将比较委托给compareto方法,但仅限于满足某些条件.在我提供的示例中,没有满足这些条件,包括isAssignableFrom检查,因为我提供的示例类(以及我的项目中给出问题的代码)是兄弟,因此不能彼此分配.
我想我明白为什么检查现在失败了,但我仍然对以下事情感到困惑:
>我该如何解决这个问题?
>这背后的理由是什么?这是一个错误还是一个设计功能?是否有任何理由说明为什么普通超类的两个子类不能相互比较?
当然还有GROOVY-4046,它显示了直接调用compareto将导致ClassCastException的情况.由于此异常是意外的,因此我们决定添加可分配性检查.
要解决此问题,您可以使用< =>相反,你已经找到了.是的,它们仍然通过DefaultTypetransformation,因此您可以比较例如int和long.如果你不想要那个,那么直接调用compareto就可以了.如果我误解了你并且你想要实际上有平等,那么你当然应该称之为等于.
总结以上是内存溢出为你收集整理的在Groovy中,为什么’==’的行为会改变扩展Comparable的接口?全部内容,希望文章能够帮你解决在Groovy中,为什么’==’的行为会改变扩展Comparable的接口?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)