【问题标题】:Prove that A == B, B==C, A != C证明 A == B, B==C, A != C
【发布时间】:2015-03-10 23:25:18
【问题描述】:

是否存在传递定律不能成立的对象或原始类型?例如

A == B, B == C 但 A != B

我不是在谈论 equals() 方法。我对 == 操作感兴趣

我们能证明这一点吗?

【问题讨论】:

  • 答案是否定的;引用相等是等价关系,所有非浮点类型上的相等是等价关系,float 和 double 上的相等是传递和对称但不是自反的。
  • @LouisWasserman 我被告知这是可以证明的,这让我很好奇
  • 我不确定“证明”在这里需要什么。 JLS 指定此属性是否足够?
  • @LouisWasserman 这将是创建一个场景,其中某种类型的对象将适用于我在问题中提到的内容。
  • 这将证明传递性不成立,但如果 A、B 和 C 都是简单标识符,传递性确实成立。您如何期望您的主张被证明是错误的? (如果你允许突变或方法调用,所有的赌注都被取消了,我怀疑奇怪的铸造废话也可能会破坏它,但那是作弊。)

标签: java algorithm logic


【解决方案1】:

给你。 A==BB==C 导致 Floats 被提升为浮动,因此 == 返回 true。但是,A==C 是引用相等,这是错误的。

    Float A = new Float(1.0f);
    float B = 1.0f;
    Float C = new Float(1.0f);
    System.out.println(A==B);
    System.out.println(B==C);
    System.out.println(A==C);

Float 在这里并不特别,它可以很容易地成为IntegerBoolean

以下是语言规范中的相关部分:

15.21.1。数值等式运算符 == 和 !=

如果相等运算符的操作数都是数字类型,或者 一个是数字类型,另一个是可转换的(§5.1.8)到 numeric 类型,对操作数执行二进制数值提升 (§5.6.2)。

15.21.3。引用相等运算符 == 和 !=

如果相等运算符的操作数都属于任一引用 type 或 null 类型,则操作为对象相等。

这是第二个反例,这次使用的事实是,比较 longfloat 是使用 float 比较完成的。

        long a = 99999999999999L;
        float b = 99999999999999.0f;
        long c = 99999999999998L;
        System.out.println(a==b);
        System.out.println(b==c);
        System.out.println(a==c);

第三,我相信即使 A、B 和 C 是同一类型,理论上也有可能存在非传递性。

如果 A 和 C 是 double-extended-exponent values (与它们最接近的双精度值 B 具有相同的值),那么在计算 A==B 和 B==C 时,语言实现可能会选择舍入 A 和 C到最接近的双精度值(即 B)。当执行 A==C 时,它同样可以选择 not 进行舍入。必须在未标记为 FP-strict 的上下文中进行比较

本质上,“5.1.13. 值集转换”为 Java 提供了一组有限的实现定义的行为,用于非 FP 严格的浮点/双精度计算,并且可以利用(至少在理论上)找到一个计数器-等式传递的例子。

【讨论】:

  • Java 中自动装箱和拆箱的概念我猜是正确的
【解决方案2】:

来自 Swift 的一个非常奇怪的例子。在这里,嵌套的可选项被包装的程度以及编译器显式解开该可选项的程度而不是参考语义起作用:

let a = nil as Int? as Int?? as? Int?
let b = nil as Int? as Int?? 
let c: Int? = nil

assert(b == a) // passes

assert(c == a && c == nil && a != nil) // passes. wtf
assert(c == b && u == nil && b != nil) // passes. wtf

【讨论】: