Java演算子のオーバーロードが必要ないのはなぜですか?Javaでサポートできる方法はありますか?
Javaでは、基本数値タイプの算術演算のみが許可されています。他のタイプ(複素数、ベクトルなど)で演算子を定義するのは便利ですが、実装に依存する特異性が常に存在するため、これはさまざまな祝福です。そのため、オペレーターは必ずしも期待どおりのことを行うとは限りません。演算子のオーバーロードを回避することにより、どの関数がいつ呼び出されるかがより明確になります。賢明なデザインは、一部の人々の目には動きます。
Javaは、言語がないため、演算子のオーバーロードを「必要」としませんneeds。
_a + b
_はa.Add(b)
の単なる「シンタックスシュガー」です(実際には、a.Add(b)
はAdd(a,b)
の単なるシンタックスシュガーであると主張する人もいます)
この関連する質問 役立つかもしれません。つまり、C++でのオーバーロードの問題のために、Javaが設計された場合、演算子のオーバーロードは意図的に回避されました。
新しいJVM言語であるScalaには、C++演算子のオーバーロードの制限なしに、演算子のオーバーロードと非常によく似たmethodオーバーロードを可能にする構文があります。 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)
言語なし必要演算子のオーバーロード。 Java wouldそれを追加することで利益が得られると信じている人もいますが、その省略は長い間利益として公表されてきたため、追加することはほぼ確実に政治的に受け入れられません(そしてそれはオラクルの買収以来、私は「ほぼ」も含めます)。
対位法は、一般に、2人の従業員を足し合わせたり、除算を行うために「+」をオーバーロードしたりするなど、意味のない(または直感に反する)オーバーロードを仮定することで構成されます。 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
の3つのトークンを受け取ります。
スペースを必要とするmightレクサーを少し単純化する-しかし、それが行った範囲では、少なくとも演算子のオーバーロードがC++の場合のように行われたと仮定すると、演算子のオーバーロードとは完全に独立しています。既存のトークンのみが使用されます1。
それで、それが問題ではない場合、何ですか?演算子のオーバーロードの問題は、演算子の意味を知るためにパーサーをハードコーディングできないことです。 Javaでは、特定の_a = b + c
_について、正確に2つの可能性があります。a
、b
、およびcはそれぞれ、限定された小さな型のセットから選択され、その意味は_+
_が言語に焼き付けられているか、エラーが発生しています。したがって、_b + c
_を調べてそれを理解する必要があるツールは、very最小限の解析を実行して、b
とc
が追加できるタイプ。もしそうなら、それは加算が何を意味するのか、それがどのような結果を生み出すのかなどを知っています。そうでない場合は、エラーを示すために赤い波線(またはその他)で下線を引くことができます。
C++の場合、状況はまったく異なります。 _a = b + c;
_のような式の場合、b
とc
はほぼ完全に任意のタイプである可能性があります。 _+
_は、b
の型のメンバー関数として実装することも、フリー関数として実装することもできます。場合によっては、いくつかの演算子のオーバーロード(一部はテンプレートである可能性があります)があり、couldその操作を実行する可能性があるため、コンパイラが実際に選択するものを決定するためにオーバーロード解決を行う必要がありますパラメータのタイプに基づいています(そして、それらのいくつかがテンプレートである場合、過負荷解決ルールはさらに複雑になります)。
これにより、_b + c
_から結果のタイプを判別できます。そこから、基本的にプロセス全体をもう一度繰り返して、その結果をa
に割り当てるために使用されるオーバーロード(ある場合)を把握します。組み込みであるか、別の演算子のオーバーロードである可能性があり、ジョブを実行できる可能性のあるオーバーロードが複数ある可能性があるため、ここで使用する適切な演算子を見つけるために、オーバーロードの解決を再度実行する必要があります。
つまり、C++で_a = b + c;
_が何を意味するかを理解するには、コンパイラフロントエンドのほぼ全体が必要です。 Java with muchコンパイラのより小さなサブセットでも同じことができます2
Java-ooコンパイラプラグイン Javaで演算子オーバーロードのサポートを追加できます。
Javaは、プログラマーによる演算子のオーバーロードをサポートしていません。これは、Javaは演算子のオーバーロードを必要としない」と述べることと同じではありません。
演算子のオーバーロードは、(算術)記号を使用して演算を表現するためのシンタックスシュガーです。明らかな理由から、Javaプログラミング言語の設計者は、言語での演算子のオーバーロードのサポートを省略することを選択しました。この宣言はJava言語環境ホワイトペーパー:
プログラマーが標準の算術演算子をオーバーロードできる手段はありません。繰り返しになりますが、演算子のオーバーロードの効果は、クラス、適切なインスタンス変数、およびそれらの変数を操作するための適切なメソッドを宣言することで、同じように簡単に実現できます。演算子のオーバーロードを排除すると、コードが大幅に簡素化されます。
私の個人的な意見では、それは賢明な決断です。次のコードについて考えてみます。
String b = "b";
String c = "c";
String a = b + c;
ここで、b
とc
が連結されてa
が生成されることはかなり明白です。しかし、演算子のオーバーロードをサポートする架空の言語を使用して記述された次のスニペットを検討すると、演算子のオーバーロードを使用しても読み取り可能なコードが作成されないことは明らかです。
Person b = new Person("B");
Person c = new Person("C");
Person a = b + c;
上記の操作の結果を理解するには、Personクラスのオーバーロードされた加算演算子の実装を確認する必要があります。確かに、それは退屈なデバッグセッションになり、コードは次のように実装する方が適切です。
Person b = new Person("B");
Person c = new Person("C");
Person a = b.copyAttributesFrom(c);
Javaは演算子のオーバーロードを「必要としない」というわけではありません。これは、言語をよりシンプルに保ちたいという作成者による選択にすぎません。
OKまあ...私たちは非常に議論された共通の問題を抱えています。今日、ソフトウェア業界には、主に2つの異なるタイプの言語があります。
この区別は約10年前に役立ちましたが、現在の状況は少し異なります。今日は、ビジネス対応のアプリケーションについて説明します。ビジネスモデルは、プログラムが多くの要件を満たす必要がある特定のモデルです。それらは非常に複雑で厳密であるため、cやc ++などの言語でアプリケーションをコーディングすると非常に時間がかかります。このため、ハイブリッド言語が発明されました。
私たちは一般的に2つのタイプの言語を知っています:
さて、今日は別のものがあります:
管理言語は、元のコードとは異なる別のコードを生成するためにコンパイルされる言語ですが、処理がはるかに複雑です。次に、この中間言語は、最終プログラムを実行するプログラムによって中断されます。
これは、Javaから知った一般的なダイナミクスです...これは、ビジネス対応アプリケーションにとって優れたアプローチです。さて、今あなたの質問に行きます...
演算子のオーバーロードは、低水準言語の多重継承やその他の高度な特性にも関係する問題です。 Java、C#、Pythonなどはマネージド言語であり、記述が簡単で、非常に短時間で複雑なアプリケーションを構築するのに役立ちます。 Javaに演算子のオーバーロードを含めると、言語はより複雑になり、処理が難しくなります。
C++でプログラムする場合、演算子のオーバーロードは非常に複雑な状況につながる可能性があり、競合などのためにコンパイラがコンパイルを拒否する可能性があるため、非常にデリケートな問題であることを確実に理解しています...演算子のオーバーロードの導入は慎重に行う必要があります。 IT IS強力ですが、処理すべき問題が非常に多く、この電力を支払っています。
OKOK IT IS TRUE、あなたは私に言うかもしれません:「ねえ、しかしC#は演算子のオーバーロードを使用しています...何を言っているのですか?なぜc#はそれらをサポートし、Javaはサポートしないのですか?」さて、これが答えです。 C#は、はい、演算子のオーバーロードを実装していますが、C++とは異なります。 「new」のようにc#でオーバーロードできない演算子や、c ++でオーバーロードできる他の多くの演算子があります...したがって、C#は演算子のオーバーロードをサポートしますが、c ++やそれを完全にサポートする他の言語よりもはるかに低いレベルです。しかし、これは前の質問に対する良い答えではありません...本当の答えは、C#はJavaよりも複雑であるということです。これは賛否両論です。それは言語をどこに置くかを決めることの問題です:高レベル、高レベル、非常に高レベル? Javaは、高速で管理と使用が簡単である必要があるため、opのオーバーロードをサポートしていません。 opのオーバーロードを導入する場合、言語はこの新しい機能によって引き起こされる大量の問題も抱えている必要があります。
「Javaが多重継承をサポートしないのはなぜですか?」という質問とまったく同じです。管理が非常に複雑だからです。考えてみてください...多重継承をサポートするマネージド言語では不可能です...共通のクラスツリー、すべてのクラスの共通の基本クラスとしてのオブジェクトクラス、アップキャストの可能性(安全)、および処理する多くの問題はありません、管理、予測、カウントを維持...
Javaはシンプルになりたいと思っています。この言語の将来の実装がopオーバーロードのサポートにつながると私が信じているとしても、オーバーロードのダイナミクスには、C++でのオーバーロードに関して持つ可能性のすべてのセットが少なくなることがわかります。
ここにいる他の多くの人も、オーバーロードは役に立たないとあなたに言いました。まあ、私はこれが真実ではないと思う人たちに属しています。そうですね、このように考えると(opのオーバーロードは役に立たない)、マネージド言語の他の多くの機能も役に立たないのです。インターフェイスやクラスなどについて考えてみてください。本当に必要ありません。インターフェイスの実装には抽象クラスを使用できます... c#を見てみましょう...非常に多くの砂糖構文、LINQなど、それらは実際には必要ありませんが、それらはあなたの仕事を固定します...まあ、管理された言語では、固定するすべてのもの開発プロセスは歓迎されており、役に立たないことを意味するものではありません。そのような機能が役に立たないと思うなら、言語全体が役に立たず、c ++、adaなどで複雑なアプリケーションをプログラミングすることになります。管理言語の付加価値は、この要素で正しく測定されます。
Opオーバーロードは非常に便利な機能であり、Javaなどの言語で実装できます。これにより、言語の構造と目的が変わります。これは良いことですが、悪いことでもあります。好みの問題です。しかし、今日、Javaはopのオーバーロードをサポートしていないため、この理由でもJavaはC#よりも単純です。
少し長かったかもしれませんが、お役に立てば幸いです。さようなら
Javaは演算子のオーバーロードをサポートしていません(1つの参照は Wikipedia演算子のオーバーロード ページです)。これは、他の言語(特にC++)での演算子のオーバーロードで見られる問題を回避するためのJavaの作成者による設計上の決定でした。
チェック Java機能がCおよびC++から削除されました p2.2.7演算子のオーバーロードがなくなりました。
プログラマーが標準の算術演算子をオーバーロードできる手段はありません。繰り返しになりますが、演算子のオーバーロードの効果は、クラス、適切なインスタンス変数、およびそれらの変数を操作するための適切なメソッドを宣言することで、同じように簡単に実現できます。演算子のオーバーロードを排除すると、コードが大幅に簡素化されます。