大家好,我是R哥。

最近看到一个非常离谱的骚操作:一个对象,竟然能同时等于两个不同的值,比如你写 JS 代码 if (obj == 10 && obj == 100),它居然能满足两个条件并打印出结果。

第一次看到这个代码,我脑袋嗡嗡的,就两个字:离谱

抱着好奇的精神研究了一番,当我搞懂背后的机制,才发现这其实是一种 巧妙利用语言特性的黑魔法,而且不仅在 JavaScript 中能玩出花来,Java 也能曲线救国整出个类似效果。

这篇文章就带大家从 JS 到 Java,掘地三尺把这个骚操作背后的本质讲清楚。

Javascript 版实现

如以下 Javascript 代码:

// 公众号:Java技术栈
var obj = {
  i: 10,
  valueOf: function() {
    if (this.i === 10) {
      this.i++;
      return 10;
    } else {
      return 100;
    }
  }
}
if (obj == 10 && obj == 100){
    console.log(obj);
}

输出结果:

{ i: 11, valueOf: [Function: valueOf] }

这里的 if (obj == 10 && obj == 100) 判断居然能同时满足?

其实这是利用了 valueOf可变返回值,第一次返回 10,第二次返回 100,所以 obj 可以做到同时等于两个不同的值!

这个对象 obj 有一个属性 i 和一个自定义的 valueOf 方法。

当你对一个对象进行如 obj == 10 这样的 非严格比较 时,JavaScript 会调用该对象的 valueOf() 方法(如果没找到,会再尝试 toString())。

第一次:obj == 10

此时 obj.valueOf() 被调用:

if (this.i === 10) { // true
  this.i++;          // i 变成 11
  return 10;         // 返回 10
}

于是 obj == 10 => 10 == 10 => ✅ 成立!

第二次:obj == 100

再次触发 obj.valueOf()

if (this.i === 10) { // false,因为 i 已经是 11
  ...
} else {
  return 100;
}

返回 100,所以 obj == 100 => 100 == 100 => ✅ 成立!


我们还可以拓展一下更骚的写法:

let obj = {
  i: 1,
  valueOf() {
    return this.i++;
  }
};

if (obj == 1 && obj == 2 && obj == 3) {
  console.log("骚操作成功!");
}

输出结果:

骚操作成功!

Java 版实现

上面那个 JS 代码的核心是利用了对象的 valueOf() 方法在 == 比较中的自动调用,每次返回不同的值,从而实现了一个对象同时等于多个不同的值。

但在 Java 中并不能直接重载 == 的行为,因为 Java 中 == 比较的是 引用地址(对象)或基本类型的值,而不能像 JS 那样 “自动调用某个方法” 来参与比较。

不过,我们可以方法 + 状态变量实现类似的效果:

/**
 * 公众号:Java技术栈
 */
public class Test {

    private int i = 10;

    public boolean equalsTo(int value) {
        if (i == 10) {
            i++; // i 从 10 -> 11
            return value == 10;
        } else {
            return value == 100;
        }
    }

    @Override
    public String toString() {
        return "MagicObject{i=" + i + "}";
    }

    /**
     * 公众号:Java技术栈
     */
    public static void main(String[] args) {
        Test obj = new Test();

        // 模拟 JS 的 a == 10 && a == 100
        if (obj.equalsTo(10) && obj.equalsTo(100)) {
            System.out.println(obj);
        } else {
            System.out.println("条件不满足");
        }
    }

}

输出结果:

MagicObject{i=11}

Java 版本也可以拓展一下更骚的写法:

/**
 * 公众号:Java技术栈
 */
public class Test {

    private int val = 1;

    public boolean equalsTo(int input) {
        return input == val++;
    }

    public static void main(String[] args) {
        Test obj = new Test();

        if (obj.equalsTo(1) && obj.equalsTo(2) && obj.equalsTo(3)) {
            System.out.println("骚操作成功!");
        }
    }

}

输出结果:

骚操作成功!

哈哈,虽然两种语言的实现原理不同,但思路一致,背后都是对 “状态变化 + 比较逻辑” 做了精心设计。

话说,这种代码有啥用?

说实话,你如果在真实项目中写出这种防御性骚代码,多半会被群起而攻之。但在面试、比赛、写博客、讲技术、装逼的时候,可能会是个绝活。

所以别只会看热闹,背后的机制才是我们真正要掌握的。

好了,今天的分享就到这里了,后面R哥会分享更多好玩的 Java 技术和最新的技术资讯,关注公众号Java技术栈第一时间推送。

版权声明: 本文系公众号 "Java技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注