Java 运算符重载(Operator Overloading)原理

2020-12-04 13:40:25 +08:00
 Braisdom

Java 语言的出现是为了降低 C++ 的开发成本和学习难,但也将 C++ 一些非常有价值的特性搞丢了,运算符重载就是一个非常优秀的特性,但 Java 搞丢了,虽然运算符重载不是一个常用特性,但随着数据分析领域的发展,表达式的编译也就有了强烈的需求。

首先,我解释一下为什么需要运算符重载,Java 是一个严谨的逻辑性编程语句,有丰富的工程化集成能力,通常 Java 编译后的代码只是 JVM 中运行,但也会在其它的可执行单元中运行,常见的有:数据库(关系型、对象型、KV 型和预计算引擎等)、也可通过是一次远程服务调用。倘若这类可执行单元的协议中存在表达式(算术、比较和逻辑),这也就意味着在 Java 中需要通过字符串的形式表现这类表达式,此时就会出现下列的代码:

目标输出协议:

"(sum(order.no) + 100) > 1000 and order.id < 999"

构造协议的 Java 代码:

and(gt(plus(funCall("sum", "order.no"), 100)), lt(fieldCall("order", "id"), 999));

对比一下将计算表达式转换为 Java 中的方法调用,变得极难理解,但这种方式也是目前大都 ORM 框架所使用的方式,这样做的方式可以使得构造过程动态化,而不是简单的字符串拼接,当然其它内部原理还是字符串拼接。

在这样的使用场景下,如果 Java 的表达式支持重载则会变的非常简单,下面是 ObjectiveSQL 的代码:

Order.Table order = Order.asTable();

Expression expr = (sum(order.no) + 100) > 1000 && order.id < 999;

其中的Expression 是实现了 Java 运算符重载,内部有种数学计算、比较和逻辑计算的相关方法,最终也是通过拼接字符串的形式输出上述目标协议。

详细可参考: https://github.com/braisdom/ObjectiveSql

如果认可项目,请点个赞,欢迎交流...

4656 次点击
所在节点    程序员
48 条回复
Braisdom
2020-12-04 13:51:29 +08:00
有兴趣的,可以交流
lewis89
2020-12-04 14:03:18 +08:00
重载运算符是一个优秀的特性???????老哥不是开玩笑吧
operate *
operate +
operate =
犹如噩梦啊,再配合 拷贝构造 引用 指针 指针的引用 右值引用 左值引用 不把脑子搞炸那还是 C++?
Braisdom
2020-12-04 14:08:20 +08:00
没有运算符重载者是恶梦的开始
wysnylc
2020-12-04 14:13:35 +08:00
xzenge
2020-12-04 14:26:32 +08:00
为什么不直接用 C++呢
no1xsyzy
2020-12-04 14:31:27 +08:00
@lewis89 使下层变复杂的同时使上层变得清晰。
Python 也能重载运算符(__add__ 等魔法方法),并且 NumPy 时常依赖重载
如果运算符重载没有使上层更清晰,那肯定是不需要重载瞎 JB 重载。
PVG
2020-12-04 14:33:55 +08:00
scala 在这一块做得很好,你可以为所欲为
lewis89
2020-12-04 14:41:11 +08:00
@no1xsyzy #6 有的时候 选择太多并不是一件好事,C++为什么被称为 horrible 的语言 就是因为选择太多了,一个 option 的选择有 3 个 另一个 option 有 3 个 再加上一个 option 的选项有 7 个 3 * 3 * 7 = 42 种选项.. 脑子都会炸
no1xsyzy
2020-12-04 14:46:18 +08:00
@wysnylc Smalltalk 是目前公认无二的最符合 OOP 思想的语言,操作符只是一种特殊的信号,可以通过 double dispatch 来重构行为
OOP 的 “代码与对象 / 类绑定” 的想法甚至比函数式更允许运算符重载(天然带 single dispatch )。
跟 OOP 没关系,但具体什么原因我就不清楚了,可能是严谨性的因素。
Braisdom
2020-12-04 14:48:29 +08:00
@PVG 认可你的想法,的确可以想干什么就干什么
Braisdom
2020-12-04 14:49:50 +08:00
@lewis89 一个语言要能跟随的时代的发展,C++ 的设计就是为了解决“我们不知道的不知道的东西”,很伟大。
Braisdom
2020-12-04 14:50:45 +08:00
@xzenge 有时候由不得你去选择,解决 Java 的运算符重载,也是被迫的
no1xsyzy
2020-12-04 14:51:24 +08:00
@lewis89 3*3*7=63 你的算数是体育老师教的罢!(ry
滥用功能与语言没关系…… checked exception 不也被 throws Exception 了……
Braisdom
2020-12-04 14:52:12 +08:00
@no1xsyzy Smalltalk 是面向对象的鼻祖,很多概念都被借鉴了,为什么不能发展起来,也是有它内在的原因
no1xsyzy
2020-12-04 14:53:45 +08:00
准确地说,运算符重载是一个 DSL-ish 的做法。
要不是现在的语言从抽象设计上都羸弱不堪,哪还需要运算符重载?来个宏就行了。
Braisdom
2020-12-04 14:54:17 +08:00
@no1xsyzy 小细节...
lewis89
2020-12-04 14:55:53 +08:00
@no1xsyzy #13 唉,年轻人啊就是没法理解我的梗,option 太多了 就算你数学是数学老师教的又能怎么样,人脑是有限的,大部分人 口算 心算 超过 2 个以上 出问题的概率激增,99 乘法表 两个一位数当然可以肌肉肌肉背诵,保证出错率低
4 个呢 5 个呢 只要复杂度在增加 人脑是肯定不够用的
no1xsyzy
2020-12-04 14:57:05 +08:00
@Braisdom 能不能发展起来从来不是内在原因决定的,是要它有能被使用的地方。
发展的意思就是参与者变多。
Braisdom
2020-12-04 14:57:15 +08:00
@no1xsyzy 我相信 Java 后面必定会支持运算符重载,虽然现在没有真实的项目在用,我是第一个,国外有几篇论文在讨论。

DSL 是一个很泛的概念,SQL 是一个 DSL,基于 Java 的 API 封装的 SQL 不一定属于 DSL 的范畴,因为它是一个高度抽象的语言,存在的只是一堆 Interface,基于 Interface 可以实现很多特性
Vedar
2020-12-04 14:58:22 +08:00
@lewis89 c++的运算符重载复杂是因为 c++ raii 的复杂,运算符重载本身对于语言表达能力是一个很大的帮助

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/732083

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX