San*_*har 14
Java仅允许对基本数字类型进行算术运算.这是一个混合的祝福,因为虽然在其他类型(如复数,向量等)上定义运算符很方便,但总是存在依赖于实现的特性.因此,运营商并不总能按照您的期望去做.通过避免运算符重载,当更加透明时调用哪个函数.一些人的眼中有明智的设计.
Java不需要"运算符重载",因为没有语言需要它.
a + ba.Add(b)(实际上,有些人认为这a.Add(b)只是语法糖Add(a,b))只是"语法糖"
这个相关问题可能有所帮助 简而言之,由于C++中的重载问题,在设计Java时有意避免了运算符重载.
Scala是一种较新的JVM语言,其语法允许方法重载,其功能与运算符重载非常相似,没有C++运算符重载的限制.例如,在Scala中,可以定义一个名为的方法+.也可以.在方法调用中省略运算符和括号:
case class A(value: Int) {
def +(other: A) = new A(value + other.value)
}
scala> new A(1) + new A(3)
res0: A = A(4)
Run Code Online (Sandbox Code Playgroud)
没有语言需要运算符重载.有些人认为Java 会因为添加它而受益,但是它的遗漏已被宣传为长期以来的好处,因此添加它几乎肯定是政治上不可接受的(并且只有在甲骨文收购之后我甚至包括"差不多").
对应点通常包括假设一些无意义(或甚至违反直觉)的重载,例如将两个雇员加在一起或重载'+'来进行分工.虽然运算符使用C++等语言进行重载可以实现这一点,但Java中缺少运算符重载几乎无法阻止甚至缓解问题. someEmployee.Add(anotherEmployee)没有改善someEmployee + anotherEmployee.同样,如果myLargeInteger.Add(anotherLargeInteger)实际上是分裂而不是添加.至少在我看来,这一论点充其量只是令人难以置信.
然而,另一方面,省略运算符重载(几乎可以肯定)具有真正的好处.它的省略使语言更容易处理,这使得开发处理语言的工具变得更容易(也更快).仅举一个明显的例子,Java的重构工具比C++更加丰富和全面.我怀疑这可以或应该被认可,仅仅是为了支持C++中的运算符重载及其在Java中的遗漏.尽管如此,保持Java简单(包括忽略运算符重载)的一般态度无疑是一个主要因素.
通过在标识符和运算符之间要求空格(例如,a+b禁止但a + b允许)来简化解析的可能性已经提出.至少在我看来,这在大多数情况下不太可能产生任何真正的差别.原因很简单:至少在典型的编译器中,解析器前面有一个词法分析器.词法分析器从输入流中提取标记并将它们提供给解析器.有了这样的结构,解析器就不会看到a+b和之间的任何差异a + b.无论哪种方式,这样会得到恰好三个令牌:identifer,+,和identifier.
需要的空间可能简化词法分析器一点点-但它没有的程度,这将是完全独立的操作符重载,至少假设操作符重载做像它是在C++中,其中仅现有令牌用于1.
那么,如果那不是问题,那是什么?运算符重载的问题在于您无法对解析器进行硬编码以了解运算符的含义.使用Java,对于某个给定的a = b + c,恰好有两种可能性:a,b和C分别由一个小的,有限的几个类型选择,并且该含义+被烤成的语言,否则你有一个错误.因此,需要一种工具来看待b + c和意义的它可以做一个非常最小的解析,以确保b和c是可以添加的类型.如果是,它知道添加意味着什么,它产生什么样的结果,等等.如果它们不是,它可以用红色曲线(或其他)强调它以指示错误.
对于C++,情况完全不同.对于表达等a = b + c;,b并c可以是几乎完全任意的类型.所述+可以被实现为的成员函数b的类型,或者它可以是一个免费的功能.在某些情况下,我们可能会有许多操作符重载(其中一些可能是模板)可以执行该操作,因此我们需要执行重载决策以确定编译器根据参数类型实际选择哪一个(如果其中一些是模板,则重载决策规则变得更加复杂).
这让我们可以确定结果的类型b + c.从那里我们基本上再次重复整个过程,以找出用于分配结果的(如果有的话)重载a.它可能是内置的,或者可能是另一个运算符重载,并且可能有多个可能的重载可以完成这项工作,因此我们必须再次进行重载解析以找出在此使用的正确运算符.
简而言之,只是弄清楚a = b + c;C++中的含义几乎需要整个编译器前端.我们可以在Java中使用更小的编译器子集2来做同样的事情
| 归档时间: |
|
| 查看次数: |
28720 次 |
| 最近记录: |