代码之家  ›  专栏  ›  技术社区  ›  Gabriel Ščerbák

操作员超载-禁止是否合理?

  •  1
  • Gabriel Ščerbák  · 技术社区  · 14 年前

    Java禁止操作符重载,但是来自C++的我没有看到任何理由。在操作员符号和其他符号一样的语言中,“+”和“加号”同样适用于“+”,没有问题。那有什么意义呢?

    编辑:为了更具体一些,请告诉我重载“+”的哪个缺点可能有重载“等于”。

    6 回复  |  直到 14 年前
        1
  •  4
  •   JUST MY correct OPINION    14 年前

    好吧,我会在假设加布里埃尔尔博K这样做是为了更好的理由,而不是为了反对一种语言而抱怨。

    对我来说,问题是可管理的复杂性:我面前的代码有多少需要解码,而不是简单地读取?

    在大多数传统语言中,当看到 a + b 我知道会发生什么。变量 a b 将被添加到一起。我很有信心,在幕后,代码将是非常简洁,非常快速的本地机器代码,将两个数字相加,无论数字是短整数还是双精度或两者的某种混合。(在某些语言中,我可能还必须假定这些字符串是连接在一起的,但这是一个完全不同的问题的咆哮——但如果你从正确的角度看它,它会使这个咆哮有味道。)

    当我创建自己的用户定义类型时——比如说无所不在的复杂类型(为什么复杂不是现代语言中的标准数据类型是 方式 超越我的地狱,但这又是对另一个问题的咆哮——如果我重载了一个操作符(或者,更确切地说,如果操作符重载了——比如说,我正在使用一个库),除了密切关注代码之外,我不知道我现在正在对对象调用(可能是虚拟的)方法,而不是拥有非常紧凑、简洁的代码生成。在幕后为我设计的。我不知道隐藏的转换,隐藏的临时变量,以及…好吧,所有与编写许多运算符相关的内容。为了找出我的代码中到底发生了什么,我必须密切关注每一行,并跟踪可能离我在代码中的当前位置有三个屏幕的声明。说这妨碍了我对代码的理解,这是轻描淡写的。重要的细节正在丢失,因为句法上的糖分使事物尝起来太美味了。

    当我被迫在对象上使用显式方法(甚至是静态方法或适用的全局方法)时,这对我来说是一个信号,当我阅读时,它告诉我潜在的开销和瓶颈等等。我 知道 我甚至不需要立刻考虑,我正在处理一个方法,我有分派开销,我可能有临时的对象创建和删除开销等等。所有事情都在我眼前——或者至少有足够的指示器在我面前,我知道要更加小心。

    我并不是本质上反对操作员过载。有时它会使代码更清晰,是的,尤其是当您对许多令人困惑的表达式进行复杂的计算时。然而,我能理解为什么有人不想把它写进他们的语言中。

    还有一个不喜欢从语言设计器的角度进行运算符重载的原因。运算符重载使语法变得非常、非常、非常困难。C++已经近乎无法理解,而且它的一些构造,如运算符重载,是它的原因。同样,从编写该语言的人的角度来看,我可以完全理解为什么不将运算符重载作为一个坏主意(或者一个在实现中很糟糕的好主意)来处理。

    (当然,除了你已经拒绝的其他原因之外,这些都是。我将提交我自己的超载 operator-,() 在我过去的C++日子里,炖菜真的很烦人。

        2
  •  7
  •   aioobe    14 年前

    正如爪哇的许多其他事情一样,这是一种限制,因为如果使用不当,可能会令人困惑。(类似于指针算法被禁止,因为它是容易出错的)。我是Java的忠实爱好者,但我通常认为它不应该仅仅因为它而被禁止。 能够 被滥用。

    例如,BigInteger将从重载+运算符中获益匪浅。

        3
  •  1
  •   Guffa    14 年前

    运算符重载本身并没有问题,但它实际上是如何被使用的。只要你超负荷的操作使它有意义,语言仍然有意义,但是如果你给操作赋予其他意义,它会使语言不一致。

    (一个例子是左移(& lt;& lt))和右移(& gt;& gt)运算符如何在C++中被重载来表示“输入”和“输出”…

    因此,排除运算符重载的原因可能是误用的风险大于运算符重载的好处。

        4
  •  1
  •   Yishai    14 年前

    我认为Java可以通过扩展其运营商来覆盖内置的数字对象类型而受益匪浅。早期的(前1.0)版本的Java据说有它(因为没有原语-一切都是一个对象),但当时的VM技术使它从性能视图中望而却步。

    但就 一般来说 允许用户定义的运算符重载,这不是Java语言的精神。主要的问题是,很难实现一个与对象类型的数学期望一致的运算符,并且它将为许多错误的实现打开大门,这些实现会导致许多难以发现(因此代价高昂)的错误。你可以看看一般Java代码中有多少坏的实现(如违反合同),问题只会从那里变得更糟。

    当然,有些语言优先考虑权力和句法美,而不是这些关注点,而且对它们来说更强大。它不是Java。

    编辑:如何自定义 + 不同于自定义的运算符 == 在爪哇中捕获 equals(Object) 方法?不是,真的。这仅仅是因为允许操作员过载,对六年级学生来说直观的东西就会变得不真实。真实世界的经验 等于(对象) 实现表明,在现实世界中,如此复杂的契约是如何难以执行的。

    进一步的编辑:让我澄清上面的内容,因为我在编辑时把它缩短了,并且失去了要点。一 + 数学中的运算符具有某些属性,其中一个属性是,无论哪边的数字出现的顺序如何,它的结果都是一样的。所以即使是最简单的 + 执行添加到集合:

      Collection a = ...
      Collection b = ...
      a + b;
      System.out.println(a);
      System.out.println(b);
    

    直观的理解 + 会导致一种期望 a + b b + a 会得出同样的结果,但当然不会。在plus方法(比如collection和string)中,开始混合两种互相作为参数的对象类型,这样就很难跟踪。

    现在可以肯定的是,在对象上设计运算符,这些对象被很好地理解,并比没有它们的情况下产生更好、更可读和更易于理解的代码。但问题是,通常情况下,在本土企业API中,您最终会看到的是模糊的代码。

        5
  •  1
  •   Martin Beckett    14 年前

    有几个问题:

    • 由于延迟计算,重载逻辑运算符会产生副作用。
    • 即使在数学类型中也存在歧义,即(3dpoint*3dpoint)是一个叉积或定标器积。
    • 您不能定义新的操作符,因此人们以新的方式重用现有的操作符,例如“string1%string2”表示在string2上拆分string1。

    但是你不能总是保护白痴不受他们自己的伤害,即使有一个明确的禁令。

        6
  •  0
  •   danben    14 年前

    关键是,每当您看到,例如,在代码中使用加号时,您就知道它所做的操作的确切含义,因为它知道它的操作数的类型(您总是在Java中执行,因为它是强类型的)。