为什么Java不提供运算符重载?

483

从C++转到Java,一个显而易见的未解之谜是为什么Java没有包含运算符重载?

难道Complex a, b, c; a = b + c;不比Complex a, b, c; a = b.add(c);简单吗?

有没有已知的原因来支持禁止允许运算符重载?这个决定的理由是任意的还是失传了?


6
可能会阅读为什么Java不支持运算符重载 - NoNaMe
1
@zzzz,我很难阅读那篇文章。这是自动翻译的吗?还是作者的第二语言是英语?我发现这里的讨论更加清晰。 - user4229245
44
关闭此问题的人认为这个问题不具建设性,但是这个问题在SO上引发了一些最有建设性的对话。也许这个问题更适合http://programmers.stackexchange.com,但有时我认为SO对更广泛的主题过于轻视。请帮我翻译这段话。 - user4229245
1
@NoNaMe,这很容易,只需在脑海中插入“a”和“the”即可。缺少冠词是一个明显的线索,表明这个人不是以英语为母语或者是程序员(或者像这个家伙一样两者都有 :))。程序员可以省略冠词的原因是这样可以使注释更短,并且更容易适应所提供的空间...从那里开始,他们就习惯了这种写法。我的问题在于布局,不知怎么的我总是在谷歌搜索中找到那个网站。幸运的是,有一个名为Clearly的很棒的Chrome扩展程序,可以很好地重新格式化难以阅读的页面。 - ycomp
1
我不明白为什么OP接受了第一个答案?@http://stackoverflow.com/users/14089/paercebal写的答案非常好,应该被采纳。 - Destructor
我希望能够为字符串重载==运算符。每次从GO、PHP、RUBY、Python等返回后,我总会犯错。 - Gellweiler
18个回答

912

有很多帖子抱怨运算符重载。

我觉得我需要澄清"运算符重载"的概念,并提供一个对这个概念的替代观点。

代码混淆?

这个论点是谬误。

在所有语言中都可以进行混淆...

在C或Java中,通过函数/方法与在C++中通过运算符重载一样容易进行代码混淆:

// C++
T operator + (const T & a, const T & b) // add ?
{
   T c ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

// Java
static T add (T a, T b) // add ?
{
   T c = new T() ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

/* C */
T add (T a, T b) /* add ? */
{
   T c ;
   c.value = a.value - b.value ; /* subtract !!! */
   return c ;
}

...即使在Java的标准接口中

举个例子,让我们看看Java中的Cloneable接口:

你应该克隆实现此接口的对象。但是你可以撒谎。并创建一个不同的对象。事实上,这个接口非常弱,你甚至可以返回完全不同类型的对象,只是为了好玩:

class MySincereHandShake implements Cloneable
{
    public Object clone()
    {
       return new MyVengefulKickInYourHead() ;
    }
}

作为可滥用/混淆的接口,应该像C++运算符重载一样被禁止吗?
我们可以重载MyComplexNumber类的toString()方法,使其返回一天中的小时数。toString()重载也应该被禁止吗?我们可以破坏MyComplexNumber.equals,使其返回一个随机值,修改操作数...等等。
在Java中,与C++或其他语言一样,程序员在编写代码时必须遵守最少的语义。这意味着实现一个添加函数add,Cloneable实现方法克隆,以及++运算符增量。
什么是混淆?
既然我们知道即使通过原始的Java方法,代码也可能被破坏,那么我们可以问一下C++运算符重载的真正用途是什么?
方法与运算符重载:清晰自然的符号表示?
我们将比较不同情况下Java和C++中“相同”的代码,以了解哪种编码风格更清晰。
// C++ comparison for built-ins and user-defined types
bool    isEqual          = A == B ;
bool    isNotEqual       = A != B ;
bool    isLesser         = A <  B ;
bool    isLesserOrEqual  = A <= B ;

// Java comparison for user-defined types
boolean isEqual          = A.equals(B) ;
boolean isNotEqual       = ! A.equals(B) ;
boolean isLesser         = A.comparesTo(B) < 0 ;
boolean isLesserOrEqual  = A.comparesTo(B) <= 0 ;

请注意,在C++中,只要提供了运算符重载,A和B可以是任何类型。在Java中,当A和B不是原始类型时,即使对于类似原始类型的对象(BigInteger等),代码也可能变得非常混乱...
自然数组/容器访问器和下标:
// C++ container accessors, more natural
value        = myArray[25] ;         // subscript operator
value        = myVector[25] ;        // subscript operator
value        = myString[25] ;        // subscript operator
value        = myMap["25"] ;         // subscript operator
myArray[25]  = value ;               // subscript operator
myVector[25] = value ;               // subscript operator
myString[25] = value ;               // subscript operator
myMap["25"]  = value ;               // subscript operator

// Java container accessors, each one has its special notation
value        = myArray[25] ;         // subscript operator
value        = myVector.get(25) ;    // method get
value        = myString.charAt(25) ; // method charAt
value        = myMap.get("25") ;     // method get
myArray[25]  = value ;               // subscript operator
myVector.set(25, value) ;            // method set
myMap.put("25", value) ;             // method put

在Java中,我们发现每个容器要做相同的事情(通过索引或标识符访问其内容),我们有不同的方法来做这件事,这很令人困惑。
在C++中,每个容器使用相同的方式访问其内容,这要归功于运算符重载。
自然高级类型操作
以下示例使用一个Matrix对象,在Google上找到第一个链接即可找到"Java Matrix object"和"C++ Matrix object"。
// C++ YMatrix matrix implementation on CodeProject
// http://www.codeproject.com/KB/architecture/ymatrix.aspx
// A, B, C, D, E, F are Matrix objects;
E =  A * (B / 2) ;
E += (A - B) * (C + D) ;
F =  E ;                  // deep copy of the matrix

// Java JAMA matrix implementation (seriously...)
// http://math.nist.gov/javanumerics/jama/doc/
// A, B, C, D, E, F are Matrix objects;
E = A.times(B.times(0.5)) ;
E.plusEquals(A.minus(B).times(C.plus(D))) ;
F = E.copy() ;            // deep copy of the matrix

这不仅限于矩阵。Java的BigIntegerBigDecimal类也遭受着同样令人困惑的冗长问题,而它们在C++中的等价物就像内置类型一样清晰明了。

自然迭代器:

// C++ Random Access iterators
++it ;                  // move to the next item
--it ;                  // move to the previous item
it += 5 ;               // move to the next 5th item (random access)
value = *it ;           // gets the value of the current item
*it = 3.1415 ;          // sets the value 3.1415 to the current item
(*it).foo() ;           // call method foo() of the current item

// Java ListIterator<E> "bi-directional" iterators
value = it.next() ;     // move to the next item & return the value
value = it.previous() ; // move to the previous item & return the value
it.set(3.1415) ;        // sets the value 3.1415 to the current item

自然函子:

// C++ Functors
myFunctorObject("Hello World", 42) ;

// Java Functors ???
myFunctorObject.execute("Hello World", 42) ;

文本连接:

// C++ stream handling (with the << operator)
                    stringStream   << "Hello " << 25 << " World" ;
                    fileStream     << "Hello " << 25 << " World" ;
                    outputStream   << "Hello " << 25 << " World" ;
                    networkStream  << "Hello " << 25 << " World" ;
anythingThatOverloadsShiftOperator << "Hello " << 25 << " World" ;

// Java concatenation
myStringBuffer.append("Hello ").append(25).append(" World") ;

好的,在Java中,您也可以使用MyString = "Hello " + 25 + " World" ; 。但是,请等一下:这是运算符重载,不是吗?这算作作弊吗?

:-D

通用代码?

同样的通用代码修改操作数,应该可用于内置/基元类型(在Java中没有接口),标准对象(可能没有正确的接口)和用户定义的对象。

例如,计算任意类型的两个值的平均值:

// C++ primitive/advanced types
template<typename T>
T getAverage(const T & p_lhs, const T & p_rhs)
{
   return (p_lhs + p_rhs) / 2 ;
}

int     intValue     = getAverage(25, 42) ;
double  doubleValue  = getAverage(25.25, 42.42) ;
complex complexValue = getAverage(cA, cB) ; // cA, cB are complex
Matrix  matrixValue  = getAverage(mA, mB) ; // mA, mB are Matrix

// Java primitive/advanced types
// It won't really work in Java, even with generics. Sorry.

讨论运算符重载

现在我们已经看到了使用运算符重载的C++代码与Java中相同代码之间的公平比较,我们现在可以讨论"运算符重载"作为一个概念。

运算符重载早在计算机出现之前就存在

即使在计算机科学之外,也有运算符重载:例如,在数学中,像+-*等运算符被重载。

的确,+-*等符号的意义取决于操作数的类型(数字、向量、量子波函数、矩阵等)。

我们大多数人在科学课程中学习了运算符的多个含义,这些含义取决于操作数的类型。那时候我们觉得它们很困惑吗?

运算符重载取决于其操作数

这是运算符重载最重要的部分:与数学或物理学一样,操作取决于其操作数的类型。

因此,了解操作数的类型,您将知道操作的效果。

即使C和Java也具有(硬编码的)运算符重载

在C中,运算符的实际行为将根据其操作数而变化。例如,添加两个整数与添加两个双精度浮点数或一个整数和一个双精度浮点数是不同的。甚至还有整个指针算术领域(不需要转换,您可以将整数加到指针上,但不能将两个指针相加...)。

在Java中,没有指针算术,但是有人仍然发现没有使用+运算符的字符串连接足够荒谬,以至于可以证明"运算符重载是邪恶的"信条存在例外。
只是你作为一个C(由于历史原因)或Java(出于个人原因,请参见下文)编码器,无法提供自己的内容。
在C++中,内置类型的运算符重载是不可能的(这是一件好事),但是用户定义的类型可以有用户定义的运算符重载。
如前所述,在C++中,与Java相反,用户类型不被认为是语言中的二等公民,而是与内置类型相比。因此,如果内置类型具有运算符,则用户类型也应该能够具有运算符。
事实上,就像Java的toString()clone()equals()方法一样(即准标准),C++运算符重载已经成为C++的一部分,就像原始的C运算符或前面提到的Java方法一样自然。
结合模板编程,运算符重载成为了一个众所周知的设计模式。事实上,在STL中,您不能在不使用重载运算符和为自己的类重载运算符的情况下走得很远。
但是,它不应被滥用。
运算符重载应该尽量遵守运算符的语义。不要在 + 运算符中减去(例如“不要在add函数中减去”,或者“在clone方法中返回垃圾”)。
类型转换重载可能非常危险,因为它们可能导致歧义。因此,它们应该真正保留给定义良好的情况。至于 &&||,除非您确实知道自己在做什么,否则不要重载它们,因为您将失去本机运算符 &&|| 所享有的短路评估。
那么......好吧......那么为什么Java中不可能呢?
因为James Gosling这样说:
我忽略了运算符重载,这是一个相当个人的选择,因为我看到太多人在C++中滥用它。
James Gosling。来源:http://www.gotw.ca/publications/c_family_interview.htm 请将Gosling上面的文本与下面的Stroustrup进行比较:
许多 C++ 的设计决策都源自于我不喜欢强制别人按照某种特定方式去做事情[...] 我经常想禁止一些我个人不喜欢的功能,但我没有这样做,因为我认为我没有权利把我的观点强加给别人。——Bjarne Stroustrup。来源:C++ 的设计与演化 (1.3 通用背景)

操作符重载对 Java 是否有益处?

一些对象会极大地受益于操作符重载(具体或数值类型,如 BigDecimal、复数、矩阵、容器、迭代器、比较器、解析器等)。

在 C++ 中,你可以从中获益,因为 Stroustrup 很谦虚。在 Java 中,你只是因为 Gosling 的个人选择而束手无策。

它能被添加到 Java 中吗?

现在在 Java 中不添加操作符重载的原因可能是内部政治、对该功能的过敏、对开发者的不信任(你知道,那些似乎总是困扰 Java 团队的破坏分子...)、与以前的 JVM 兼容性、编写正确规范的时间等。

所以不要指望这个功能能够很快被添加到 Java 中...

但是他们在 C# 中做到了!!!

是的...

虽然这远非两种语言之间唯一的区别,但这个区别总是让我感到有趣。

显然,C# 的人们通过他们的 "每个基元都是一个结构体,并且结构体派生自 Object",第一次尝试就做对了。

他们也可以用其他语言来做到这一点!!!

尽管有很多关于使用自定义运算符重载的FUD,但以下语言支持它:KotlinScalaDartPythonF#C#DAlgol 68SmalltalkGroovyRaku(前身为Perl 6),C ++,RubyHaskellMATLABEiffelLuaClojureFortran 90SwiftAdaDelphi 2005...

有这么多语言,它们有各自不同(有时甚至相反)的哲学观点,但它们都在这一点上达成了共识。

值得深思...


57
这是一个很棒的回答。我不同意它,但它仍然是一个很棒的回答。 我认为,糟糕的重载可能带来的问题超过了好的重载所带来的价值。 - Douglas Leeder
84
@Douglas Leeder:谢谢!运算符重载就像面向对象编程一样。第一次学习时,您会像将基类和继承放到各个地方一样,到处写重载(就像 Java API 一样,甜蜜的反讽)。但这很快就过去了,然后您会欣赏到这种可能性,同时不滥用它。我自己对 C++ 的十年以上经验是,我在我的代码和其他程序员的代码中看到的坏重载数量非常少,我相信我可以用一只手数清楚。而这比使用 sprintf、strcat、memset 和缓冲区溢出的总错误数量要少得多。 - paercebal
13
我相信,在另一个SO问题中讨论过后,"爱好者"和"反对者"的运算符重载观念之间的差距可能是由于他们对代码的不同处理方式所导致的:"反对者"更加关注"功能至上",意味着他们期望函数只做一件事情。因此,运算符应该按照语言设计的方式工作;而"爱好者"则更关注"对象应该如何表现",意味着他们更容易接受函数(因此,运算符)可以根据其参数类型改变行为。 - paercebal
126
史诗级回答。这是我读过的最有资质的揭穿之一。 - Sebastian Mach
7
请问您需要的翻译是:@MaartenBodewes : 我之前写的所有例子,以及让你感到困扰的是“作为开发者,你会因为Gosling的个人选择而束手无策”这一点吗?请您撰写自己的回答,支持“你们开发者很蠢,让天才人物为你们决定需要什么”的角度。这个讨论没有任何意义。 - paercebal
显示剩余41条评论

44

詹姆斯·高斯林(James Gosling)将设计Java比作以下内容:

“关于移动有一个原则,当你从一个公寓搬到另一个公寓时。一个有趣的实验是把你的公寓打包放在盒子里,然后搬进下一个公寓,直到你需要它才不需要拆箱。所以你做第一顿饭时,你从盒子里拿出东西。然后大约一个月后,你就用这个方法基本上找出了你生活中真正需要的东西,然后你把剩下的东西 - 不管你喜欢多少或者多酷,你就把它扔掉。惊人的是,这简化了你的生活,你可以在设计问题中运用这个原则:不要只是因为事情很酷或很有趣而去做。”

您可以在此处阅读该引用的上下文。

基本上,操作符重载非常适合模拟某种点、货币或复数的类。但在此之后,您会很快耗尽例子。

另一个因素是C++特征被开发人员滥用,例如对'&&', '||', 转换操作符以及当然还有'new'进行操作符重载。结合传值和异常使用带来的复杂性在《Exceptional C++》一书中得到了很好的阐述。


6
请提供一个关于“运算符重载复杂性与值传递和异常相结合”的代码示例。尽管我已经使用该语言几年,并拥有并阅读了所有关于C++的有效/异常书籍,但我仍然没有理解你所说的内容。 - paercebal
71
詹姆斯·高斯林的做法并不适用于所有人。他因为将他的“有趣”的打包实验推而广之,而变得非常短视,认为应该“扔掉我不需要的一切东西,这样其他人也不能使用那些东西。”他显然不知道我需要什么或者在使用什么。 - B T
54
与Stroustrup的观点相比,Gosling的观点最具启发性:“许多C++设计决策都源于我不喜欢强迫别人以某种特定的方式做事情[...]我经常想禁止我个人不喜欢的功能,但我没有这样做,因为我认为我没有权利把我的观点强加给别人。”(B. Stroustrup)。 - paercebal
29
@Software Monkey: "C++,广泛受到诟病,而其他语言 Java 却广受欢迎" 这是营销炒作。请记住,C++ 是独自发展的,而 Java(和 .NET)则受益于营销推广。Java 被称为“广受喜爱的语言”,但它只用于服务器应用,而“广受诟病”的 C++(可能是被想要降低代码生产成本的 Java 开发人员和经理所诟病)则可用于高性能服务器和高性能游戏等多个领域。[...] - paercebal
17
@Hassan:每种语言都有其技巧,Java的泛型就是其中一个很好的例子。现在,关于“我希望他们去看看一些用奇怪技巧和语言‘非凡’特性编写的C++代码”:无论使用哪种语言,不好的程序员都会写出糟糕的代码。试着在Java中模拟函数参数的“按引用传递”就能想象出来。我曾经看过这样的代码,笑得肚子疼。这是Gosling没有使用的东西,在Java中需要可怕的技巧才能实现,但在C#和C++中却是本地存在的,而且零成本。 - paercebal
显示剩余19条评论

24

看看Boost.Units:链接文字

它通过操作符重载提供零开销的量纲分析。还有什么比这更清晰的呢?

quantity<force>     F = 2.0*newton;
quantity<length>    dx = 2.0*meter;
quantity<energy>    E = F * dx;
std::cout << "Energy = " << E << endl;

实际输出为"能量= 4焦耳",这是正确的。


1
“它究竟如何使维护变得复杂,这又在哪里使代码变得晦涩难懂?” - Mooing Duck

15
Java的设计者认为,操作符重载带来的麻烦超过了它的价值。就是这么简单。
在一个每个对象变量实际上都是引用的语言中,操作符重载会带来额外的危险,对于C++程序员来说,这是相当不合逻辑的。将其与C#的"=="等号操作符重载以及Object.EqualsObject.ReferenceEquals进行比较。

12

假设你想要覆盖由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= 执行引用复制,因此ab现在引用相同的值。结果,比较将产生"相等",因为对象将与自身比较相等。

副本和引用之间的差异只会增加运算符重载的混淆。正如@Sebastian提到的那样,Java 和 C#都必须分别处理值和引用相等性-- operator+ 可能需要处理值和对象,但operator= 已经实现了处理引用。

在 C++ 中,你应该始终只处理一种类型的比较,这样会更少的混淆。例如,在Complex上,operator=operator== 都是处理值 - 复制值和比较值。


7
其实很简单,就像Python一样,不要有重载赋值。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
257
这个回答根本没有回答问题。你只是在强调java使用等号的情况。如果b + C返回一个新的复数,那么a = b + c就完全有效了,而且更容易阅读。即使你想直接修改a,a.set(b + c)也更容易阅读 - 特别是当算术不止是微不足道时:a.set((ab + bc)/5) 或 a = a.multiply(b).add(b.multiply(c)).divide(5)。你决定。 - B T
27
或许...这不是你的选择,情况可能如此。 - B T
9
在C++中,表达式模板解决了额外复制的问题。 几乎所有主要的算术库都使用这种技术来解决这个问题。此外,这并没有回答问题,因为a = b + c只是a.foo(b.bar(c))的语法糖,而这实际上是问题的最初观察结果。 - Kaz Dragon
22
这不是对所提问题的答案。这是有关Java和C++之间某些差异的某人的猜测。 - SChepurin
显示剩余5条评论

9

Groovy具有运算符重载功能,并且可以在JVM上运行。如果您不介意性能损失(这种损失每天都在减小),它会根据方法名称自动执行。例如,'+'调用'plus(argument)'方法。


4
我希望所有语法繁重,使用运算符重载的编程语言都能采用这种技术。我一直不明白为什么他们要发明一个特殊版本的方法命名和查找。Stroustrup在D&EC ++中没有提到任何替代方案。 C#团队采用了Linq语法的正确方法(where ... 变成 .Where(i => ... )。如果他们也用算术运算符做同样的事情,那么很多事情将变得更简单而且更强大。Java拥有一个干净的起点,可以做到这一点(尽管出于宗教原因,它可能永远不会这样做)。 - Daniel Earwicker
@DanielEarwicker,我经常注意到当有复杂的分歧时,人们会将双方的动机标记为“宗教性质”。 - user4229245
@noah,如果有一个特殊的标记来保持方法名称在视觉上的区别,我可以接受一种有限的运算符重载子集,比如定义一个__plus()方法来实现"+" OL,远离像转换和甚至数组下标这样的重载。但我无法接受C++和C#实现它的方式。 - user4229245
2
不是答案。VM上运行着许多语言。仅仅因为操作符重载而更换语言并不是一个好的理由。 - Maarten Bodewes

8

有些人说在Java中进行运算符重载会导致混淆。但是这些人是否曾经停下来看过一些Java代码,比如使用BigDecimal对金融价值增加百分比的基本数学计算?……这种练习的冗长程度成为了混淆的证明。具有讽刺意味的是,在Java中添加运算符重载将允许我们创建自己的货币类,使这样的数学代码变得优雅而简单(不再混淆)。


BigDecimal确实是操作符重载的主要原因,每个金融/会计应用程序都存在这种可读性问题。 - undefined

5

我认为这可能是一种有意的设计选择,旨在强制开发人员创建其名称清晰表达其意图的函数。在C++中,开发人员会重载运算符,并赋予与给定运算符的通常接受性质完全不相关的功能,使得几乎不可能在不查看运算符定义的情况下确定代码的作用。


15
在C++中,开发者会通过重载操作符来实现一些与操作符本身常规意义无关的功能。这是一个过度断言。我是一名从事C++开发12年的专业人士,很少遇到这个问题。事实上,我在C++中看到的大多数错误和设计问题都出现在类似于C风格的代码中(如void *,强制类型转换等)。 - paercebal
7
每个你赋值的变量都是一个符号,就像算术运算符的符号一样。无论你使用短语来给那个变量命名、使用一个单词或一个单个的字母,这是你(或你团队)的决定。谁能说什么是有意义的,什么不是?答案是你,程序员。在纯数学中,矩阵之间的乘法与基本算术中两个数字之间的乘法意义不同。然而我们对于这两种类型的乘法使用相同的符号。 - Engineer
2
@paercebal:不幸的是,这个断言是正确的。你只需要看一下IOstreams就可以看到它在发挥作用了。值得庆幸的是,大多数开发人员对于为现有运算符发明新语义更加谨慎。 - Ben Voigt
5
@BenVoigt:[...] 我甚至没有提到 add 函数可能会被非常滥用(比如做乘法,或获取互斥锁)... 用户14128提到的滥用不限于运算符,但是有一种关于运算符重载的病态恐惧感,我认为这源自 C 和 C++ 早期的竞争。这种恐惧一直延续到了 Java,但幸运的是没有出现在 C# 中... 最终,尊重语义并编写清晰的函数/运算符是开发人员的工作,而不是语言的责任。 - paercebal
3
示例代码 cout << f() || g() 中的括号并没有使其更清晰,而是使其正确。如果没有滥用位移操作符,它们就不是必要的。为什么 cout << (5&3) << endl;cout.fmt(5&3)(endl); 更好?在流中使用函数调用运算符与成员变量结合会比仅仅因其外形美观而重用位运算符更好。但这远非流设计中唯一的问题。 - Ben Voigt
显示剩余11条评论

5
从技术上讲,每种可以处理不同类型数字的编程语言都存在运算符重载,例如整数和实数。解释:重载一词意味着对于一个函数,有几个不同的实现方式。在大多数编程语言中,为运算符+提供了不同的实现方式,一个用于整数,一个用于实数,这称为运算符重载。
现在,许多人觉得Java为将字符串连接起来的操作符+提供了重载很奇怪,从数学的角度来看,确实很奇怪,但是从编程语言开发者的角度来看,为其他类(例如String)添加内置的运算符重载并没有什么问题。然而,大多数人认为,一旦你为String添加了内置的+过载,那么为开发者提供这种功能通常是一个好主意。
我完全不同意运算符重载会导致代码混淆的谬论,因为这取决于开发者自己决定。这种想法是幼稚的,说实话,这已经过时了。
赞成在Java 8中添加运算符重载。

1
在我看来,Java使用+连接任何字符串都相当丑陋,C和FORTRAN中/的重载也是如此。在许多版本的Pascal中,对任何数字类型使用算术运算符将产生数值上等同于将操作数转换为“Real”的结果,尽管可能不是整数的结果必须通过TruncRound进行处理,然后才能分配给整数。 - supercat

4
说运算符重载会导致逻辑错误,因为运算符不匹配操作逻辑,这就像是在说无事。如果函数名称与操作逻辑不合适,则会发生相同类型的错误 - 那么解决方案是什么:放弃使用函数的能力吗!这是一个滑稽的答案 - “不适合操作逻辑”,每个参数名称、每个类、函数或其他任何东西都可能在逻辑上不合适。 我认为这个选项应该在受人尊敬的编程语言中可用,而那些认为它不安全的人 - 嘿,没有人说你必须使用它。 让我们以C#为例。他们放弃了指针,但是嘿 - 有“不安全代码”语句 - 自己承担风险进行编程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接