为什么不Java提供操作人员超载?
-
09-06-2019 - |
题
来自C++Java,很明显悬而未决的问题是你为什么不Java包括操作者负载过重?
是不是 Complex a, b, c; a = b + c;
多简单 Complex a, b, c; a = b.add(c);
?
是有一个已知原因,有效的论据 不 允许操作人员超载?的原因是任意的,或丢失的时间?
解决方案
假设你想要的复盖上一个值的对象称,由 a
, 然后一件功能,就必须援引。
Complex a, b, c;
// ...
a = b.add(c);
C++,这表情告诉编译器,以创建的三(3)目的在于堆叠,执行外,以及 复制 所得数值从临时目纳入现有的对象 a
.
然而,在爪哇, 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++,这份价值,因此比较将会导致不平等。在爪哇, operator=
执行基准的副本,所以 a
和 b
现在参照同样的价值。其结果是,比较会产生'平等',因为对象会比较平等本身。
之间的差副本,并引用只会增加混乱的操作超载。作为@提到塞巴斯蒂安、Java和C#既要处理的价值和平等的参考分别-- operator+
将有可能处理的价值观和目,但是 operator=
已经实施处理引用。
C++,你应该只处理一种比较,在一段时间,所以可以下令人困惑。例如,上 Complex
, operator=
和 operator==
都是工作上的价值观--复制的价值观和值的比较分别。
其他提示
有很多的员额抱怨操作超载。
我觉得我必须澄清"经营者超载"的概念,提供一种替代的观点这一概念。
代码混淆?
这一论点是一种谬论。
混淆是能够在所有的语言...
它是作为容易混淆的代码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 ;
}
...甚至中爪哇的标准接口
对于另一个例子,让我们来看看 Cloneable
接口 在Java:
你应该克隆的对象执行这一界面。但你可以说谎。并创建一个不同的对象。事实上,这种接口是如此虚弱你可能返回另一种类型的对象,只是它的乐趣:
class MySincereHandShake implements Cloneable
{
public Object clone()
{
return new MyVengefulKickInYourHead() ;
}
}
作为 Cloneable
接口可以被滥用/模糊处理的,它应该被禁止基于同样的理由C++操作人员超载的是应该是什么?
我们可能超载 toString()
方法中的一个 MyComplexNumber
类有回报的化小时的一天。应该的 toString()
超载被禁止的?我们可以破坏 MyComplexNumber.equals
有这回一个随机的价值,修改操作数...等等。等等。等等.
在爪哇,作为在C++、或任何一种语言,编程人员必须遵守的最低语的时候编写代码。这意味着实现一个 add
功能,增加了, Cloneable
执行方法,克隆,和一个 ++
操作员的比增加。
有什么混淆的?
现在我们知道,代码可以被破坏,甚至通过的原始Java方法,我们可以扪心自问有关实际使用的操作人员超载在C++?
清晰自然的符号:方法与操作员负载过重?
我们将比较下,对于不同的情况下,"相同"的代码中爪哇和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 ;
请注意,A和B可能是任何类型的用C++,只要操作超载。在爪哇,当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
在爪哇,我们看到,对每个容器的做同一件事(取其内容通过一个指数或标识),我们有一个不同的方式做到这一点,这是令人困惑。
在C++、每个容器使用的相同的方式来访问其内容,由于操作超载。
自然先进类型的操纵
下面的例子使用 Matrix
目的,发现使用的第一个找到的链接,在谷歌"Java矩阵的目的"和"c++矩阵的目的":
// 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
这并不是限于矩阵。的 BigInteger
和 BigDecimal
类的Java遭受的同样的混乱的详细程度,而其等同物,在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") ;
Ok,在Java可以使用 MyString = "Hello " + 25 + " World" ;
太...但是,等一下:这是操作者负载过重,不是吗?它不是作弊的???
:-D
通用代码?
相同的通用代码修改操作数应该可以使用这两个用于建ins/元(其没有接口在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++编码使用的操作者负载过重,同样的代码,我们现在可以讨论"运载"作为一个概念。
操作人员超载的存在,因为在计算机之前
即使外部的计算机科学的,还是操作者负载过重:例如,在数学、运营商喜欢 +
, -
, *
, 等等。超载。
事实上,意义的 +
, -
, *
, 等等。变化取决于这种类型的操作数(数字、向量、量子波的功能,矩阵等)。
我们中的大多数,作为我们的科学课程,学会了多种定义这些对运营商,根据该类型的操作数。我们找到他们困惑,他们吗?
操作员负载过重取决于其操作数的
这是最重要的组成部分的操作者负载过重:像数学,或在物理、操作上取决于其操作数'类型。
因此,知道是什么类型的操作数,并且您将知道效果的运作。
甚至C和Java有(硬编码)操作人员超载
在C,真正行为者的操作将根据其操作数。例如,增加两个整数的不同比增加两倍,或者甚至是一个整数和一张双人床。甚至还有整个指针算域(而不铸造的,你可以添加一个指整数,但是你不能添加两个指...).
在爪哇,没有指针算,但有人仍然发现串联无 +
操作员将是荒谬的,足以证明一个例外"运载是邪恶"的信条。
这只是你作为一个C(由于历史的原因)或Java(对 个人原因, 见下文)的编码,你不能提供自己的。
C++、操作员的过载是不是可有可无的...
C++、操作人员超载的建筑类型是不可能的(这是一件好事),但是 用户定义的 类型可以有 用户定义的 算过载.
正如已经早些时候所说,在C++,并对违反Java、用户类型不被视为二等公民的语言,比较时以内在的类型。因此,如果建立类型有运营商、用户类型应该能够有他们。
真相是这样的 toString()
, clone()
, equals()
方法都是为Java(即准标准)、C++算过载是多么的一部分C++它成为作为自然作为原始经营者,或者在之前提到的Java方法。
结合模板编程中,操作人员超载的成为一个众所周知的设计图案。事实上,你不能走得很远在STL没有使用过载运营商,并载经营者为自己的类。
...但是它不应该被滥用
操作员负载过重,应该努力尊重的义的操作者。不减一个 +
操作员(如在"不减在一个 add
功能",或"返回在废话 clone
方法").
铸过载可能是非常危险的,因为它们可以导致含糊之处。因此,他们真正应该保留用以及定义的情况下。作为对 &&
和 ||
, ,永远不要超载它们,除非你真的知道你在做什么,你就会失去短路评估本机运营商 &&
和 ||
享受。
所以...好...那么为什么它不可能在Java?
因为詹姆斯的小鹅这么说的:
我离开了操作人员超载的作为 相当个人选择 因为我已经看过太多的人滥用它在C++。
詹姆斯*高斯林。资料来源: http://www.gotw.ca/publications/c_family_interview.htm
请比较高斯林的文本上与Stroustrup的下:
许多C++设计的决定,其根源在我不喜欢对于迫使人们要做的事情,在某些特定方式[...]常常,我忍不住要取缔一个特点,我不喜欢,我没有这样做因为 我不认为我有权强迫我的意见其他人.
Bjarne Stroustrup.资料来源:在德兴和演变C++(1.3一般背景)
会员超载的受益Java?
一些对象将极大地受益于操作人员超载(混凝土或数类型,如BigDecimal、复杂的数字、基质、容器、迭代器、比较,分析器等)。
C++,你可以从这一有益的,因为Stroustrup的谦卑。在爪哇,你只需旋,因为高斯林的 个人的选择.
它可能加入到Java?
原因不加入操作人员超载现在Java可能是一个混合的内部政治、过敏的功能,不信任的开发人员(你知道,那些破坏者似乎困扰着Java队...)、兼容性,与前一Jvm,时间编写正确规格,等等。
所以不要屏住呼吸,等待这个功能...
但他们这样做C#!!!
是啊...
虽然这远远不是唯一的区别之间这两种语言,这个从来没有逗我。
显然,C#伙计们,与他们的 "每一个原始是 struct
, 和一个 struct
来自对象", ,得到了它在第一次尝试。
和他们做的 其他语言!!!
尽管所有形成的阻挠者阵营针对使用定义的操作者负荷超载,下列语言支持它: 斯卡拉, 镖, 蟒蛇, F#, C#, D, 陵68, 一般, 时髦的, Perl6, 、C++、 红宝石, Haskell, MATLAB, 艾菲尔铁, Lua, 题, Fortran90, Swift, Ada, 德尔菲2005年...
所以许多种语言,所以许多不同的(有时相对)的哲学,但他们都同意这一点。
思考的食粮...
詹姆斯*戈斯林比作设计Java如下:
"还有这一原则有关的移动,当你从一个公寓里给另一个公寓。一个有趣的实验,是为了收拾你的公寓并把一切都在盒子里,然后进入下一个公寓,而不拆开任何东西,直到你需要它。所以你让你的第一餐,和你拉出来的东西一个盒子。然后一个月后,或所以你使用对很多图找出是什么东西在你的生命你的实际需要,然后你把剩下的东西--忘了你有多喜欢它,或者如何很酷它是--你只是把它扔掉.这是多么惊人的,它简化了你的生活,并且可以使用这一原则在各种设计问题:不做的事情只是因为他们很酷,或只是因为他们是有趣的。"
你可以阅读 下文的报价在这里
基本上算过载是伟大的类型的某种点,货币或复杂的数量。但在那之后你开始运行的例子快。
另一个原因是滥用的特点在C++通过开发人员超载运营商喜欢'&&', '||', 铸运营商和"新"。复杂性导致的结合这与传值和例外情况是众所涵盖的 特殊C++ 书。
检查了提升。单位: 链接文本
它提供了零开销的尺寸分析通过操作超载。如何更加清晰可以这得到什么?
quantity<force> F = 2.0*newton;
quantity<length> dx = 2.0*meter;
quantity<energy> E = F * dx;
std::cout << "Energy = " << E << endl;
实际上会出"能源=4J",这是正确的。
Java设计师的决定,操作者负载过重的是更多的麻烦比它的价值。就这么简单。
在语言在每个对象变量实际上是一个参考,操作人员超载得到的额外风险是相当不合逻辑-C++编程人员至少。比较的情况的C#'s==operator超载 Object.Equals
和 Object.ReferenceEquals
(或者任何它被称为).
时髦的 具有操作员超载和运行中的JVM。如果你不介意的性打击(其每天都变得更小).这是自动的基础的方法的名称。例如,'+'话'的加(参数)'法。
我觉得这可能是一个有意识的设计的选择的力开发人员来创建职能,其名称清楚地传达他们的意图。在C++开发人员会过载运营商与功能,这将常常没有关系到普遍接受的性质给予的操作者,使其几乎不可能确定什么是一段代码并不看的定义操作人员。
嗯,你真的可以搬起石头砸自己的脚操作超载。这就像指针人们做出愚蠢的错误与他们所以它决定把剪刀走。
至少我觉得这就是原因。我在你这一边了。:)
他说,操作人员超载,导致逻辑上的错误类型的操作员不匹配的逻辑操作,它就像什么也没说。相同类型的错误会发生,如果功能的姓名是不合适的运作逻辑-那么,有什么解决方案:下降的能力的功能使用的!?这是一个滑稽的答案-"不适当的运作逻辑",每一个参数的名字,每一类、功能或任何可logicly不适当的。我认为,这种选择应该是在尊敬的编程语言的,和那些认为这是不安全-嘿没有私人楼说你必须要使用它。可以采取的。他们下垂的指针,但是,嘿-那是'不安全代码声明的程序,因为你喜欢在你自己的风险。
一些人说,操作人员超载在Java将导致obsfuscation.有些人曾经停下来看看有些代码做一些基本的数学等增加一个财务价值的百分比使用BigDecimal?....的详细程度这项工作成为其自己的示范obsfuscation.具有讽刺意味的是,增加操作人员超载的Java将使我们能够创造我们自己的货币类会做出这样的数学码和简单的(小obsfuscated).
从技术上讲,那是操作人员超载在每种编程语言,可以处理不同类型的数字,例如整和真实的数字。说明:术语载意味着只是有几个实现一个功能。在大多数编程语言不同的实施提供运营商+,一个对于整数,一个用于实,这就是所谓的操作超载。
现在,很多人觉得很奇怪,Java具有操作员超载于操作对于加入串在一起,并从数学角度来看,这将是奇怪的,事实上,但看出,从一种编程语言开发的角度来看,有什么错添加内置的操作员超载于操作人员对于其他类例如String.然而,大多数人同意,一旦添加内置超载为+for String,然后它是一个好主意提供这种功能的开发。
一个完全不同意的谬误,操作人员超载的混淆代码,因为这是离开的开发人员来决定。这是天真的认为,可以很诚实,它是越来越老了。
+1添加操作人员超载在Java8.
假设Java作为实现语言,然后a、b和c将所有被引用类型复杂的最初价值为零。还假定是不可改变的复杂的提及 BigInteger 以及类似的不可改变的 BigDecimal, 我我想你是说下,你将参照的复杂的返回加入b和c,并不比该参考。
不是:
Complex a, b, c; a = b + c;
很多 简单:
Complex a, b, c; a = b.add(c);
有时,它将是很好的操作者负载过重,朋友班和多个继承。
但是我仍然认为这是一个很好的决定。如果Java会有操作人员超载的那么我们永远不可能确定操作者的含义没有看源代码。目前,没有必要的。我认为你的例的使用方法,而不是操作者负载过重,也是相当的可读性。如果你想使事情更清楚你总是可以添加上述的毛茸茸的发言。
// a = b + c
Complex a, b, c; a = b.add(c);
这不是一个很好的理由来禁止它但是实际一:
人们并不总是使用它的责任。看看这个例从Python库scapy:
>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>
这里是解释:
有/运营商已经作为一个组成员之间两个 层。这样做时,低层可能有一个或多个其 默认字段重载根据上层。(你还是 可以得到你想要的值).一串可以作为一个原层。