如何违反Comparable接口第一次提供整数溢出?

时间:2012-07-26 16:24:12

标签: java comparable effective-java

java.lang.Comparable#compareTo方法声明为第一条

  

实现者必须确保sgn(x.compareTo(y))== -sgn(y.compare-   至(x))所有x和y。 (这意味着x.compareTo(y)必须抛出   当且仅当y.compareTo(x)抛出异常时才会出现异常。)

并根据约书亚布洛赫在第12项的有效Java中的说明

  

这个技巧在这里工作正常,但应谨慎使用。   除非您确定有问题的字段,否则请勿使用它   非负面的,或者更一般地说,是否存在差异   最低和最高可能字段值小于或等于   Integer.MAX_VALUE(231-1)。这个技巧并不总是奏效的原因   是一个有符号的32位整数不足以容纳   两个任意有符号32位整数之间的差异。如果我是   大的正int和j是一个大的负int,(i - j)会   溢出并返回负值。生成的compareTo方法   将返回一些参数的错误结果并违反第一个参数   和compareTo合同的第二条款。这不是纯粹的   理论问题:它在实际系统中引起了失败。这些   失败可能很难调试,因为破坏的compareTo方法   适用于大多数输入值。

如果整数溢出,你可以违反第一条规定而我无法找到,这个例子说明了第一条规定将如何被违反:

public class ProblemsWithLargeIntegers implements Comparable<ProblemsWithLargeIntegers> {

    private int zas;

    @Override
    public int compareTo(ProblemsWithLargeIntegers o) {
        return zas - o.zas;
    }

    public ProblemsWithLargeIntegers(int zas) {
        this.zas = zas;
    }

    public static void main(String[] args) {
      int value1 = ...;
      int value2 = ...;
      ProblemsWithLargeIntegers d = new ProblemsWithLargeIntegers(value1);
      ProblemsWithLargeIntegers e = new ProblemsWithLargeIntegers(value2);
      if (!(Math.signum(d.compareTo(e)) == -Math.signum(e.compareTo(d)))){
        System.out.println("hey!");
    }

}

所以我想要value1value2来获取它?任何的想法?或约书亚错了?

1 个答案:

答案 0 :(得分:3)

嗯,这违反了一般合同。例如,取value1 = Integer.MIN_VALUEvalue2 = 1。这将有效地报告Integer.MIN_VALUE > 1

编辑:实际上,我错了 - 很容易违反第一条规定:

int value1 = Integer.MIN_VALUE;
int value2 = 0;

两次比较都会得到否定结果,因为Integer.MIN_VALUE - 0 == 0 - Integer.MIN_VALUE