大家好,我是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技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。