从c++到Java,一个显而易见的未回答的问题是为什么Java没有包含操作符重载?
复合物不是a b c吗?A = b + c;比复合物a, b, c简单得多;A = b.add(c);?
是否有一个已知的原因,不允许操作符重载的有效参数?理由是随意的,还是被时间消磨了?
从c++到Java,一个显而易见的未回答的问题是为什么Java没有包含操作符重载?
复合物不是a b c吗?A = b + c;比复合物a, b, c简单得多;A = b.add(c);?
是否有一个已知的原因,不允许操作符重载的有效参数?理由是随意的,还是被时间消磨了?
当前回答
有时,操作符重载、友类和多重继承会很好。
然而,我仍然认为这是一个很好的决定。如果Java有运算符重载,那么如果不查看源代码,我们就永远无法确定运算符的含义。目前还没有必要。而且我认为你使用方法而不是操作符重载的例子也是相当可读的。如果你想让事情更清楚,你总是可以在烦人的语句之上添加注释。
// a = b + c
Complex a, b, c; a = b.add(c);
其他回答
我认为人们在做决定时忘记了复杂的值、矩阵代数、集合论和其他情况,因为重载可以使用标准的符号,而不用把所有东西都构建到语言中。无论如何,只有面向数学的软件才能真正受益于这些特性。一般的客户应用程序几乎不需要它们。
当程序员定义一些特定于程序的操作符时,这些关于不必要混淆的参数显然是有效的,而这些操作符可能是函数。函数名在清晰可见时,提供了函数名存在的提示。运算符是一个没有可读名称的函数。
Java通常是按照这样的理念设计的:一些额外的冗长并不是坏事,因为它使代码更具可读性。具有相同功能的构造只需输入更少的代码,过去被称为“语法糖”。这与Python的哲学非常不同,例如,在Python哲学中,更短的几乎总是被视为更好的,即使为第二个读者提供的上下文更少。
你可能真的会搬起石头砸自己的脚。这就像指针一样,人们会犯愚蠢的错误,所以我们决定把剪刀拿走。
至少我认为这是原因。 反正我是站在你这边的。:)
我认为这可能是一个有意识的设计选择,迫使开发人员创建的函数的名称清楚地表达了他们的意图。在c++中,开发人员会用与给定操作符的普遍接受性质无关的功能重载操作符,这使得不查看操作符的定义几乎不可能确定一段代码的功能。
假设您想要覆盖a所引用的对象的先前值,那么必须调用成员函数。
Complex a, b, c;
// ...
a = b.add(c);
在c++中,这个表达式告诉编译器在堆栈上创建三(3)个对象,执行加法,并将结果值从临时对象复制到现有对象a中。
然而,在Java中,operator=并不为引用类型执行值复制,用户只能创建新的引用类型,而不能创建值类型。因此,对于名为Complex的用户定义类型,赋值意味着将引用复制到现有值。
考虑:
b.set(1, 0); // initialize to real number '1'
a = b;
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail
在c++中,这将复制值,因此比较结果将是不相等的。在Java中,operator=执行引用复制,因此a和b现在引用相同的值。结果,比较将产生'equal',因为对象的比较结果将等于自身。
复制和引用之间的差异只会增加操作符重载的混乱。正如@Sebastian所提到的,Java和c#都必须分别处理值和引用相等——operator+可能会处理值和对象,但operator=已经被实现来处理引用。
在c++中,一次只能处理一种比较,这样就不会那么令人困惑。例如,在Complex上,operator=和operator==都处理值——分别复制值和比较值。
有时,操作符重载、友类和多重继承会很好。
然而,我仍然认为这是一个很好的决定。如果Java有运算符重载,那么如果不查看源代码,我们就永远无法确定运算符的含义。目前还没有必要。而且我认为你使用方法而不是操作符重载的例子也是相当可读的。如果你想让事情更清楚,你总是可以在烦人的语句之上添加注释。
// a = b + c
Complex a, b, c; a = b.add(c);