web-dev-qa-db-ja.com

Java-戻り値型に基づくメソッドのオーバーロードがないのはなぜですか?

私はこれが不可能であることを知っていますが、Javaがこれをサポートしないことを選択した理由を教えてください。私が考えるそれはいいですね。

43
llm

Javaでメソッドの戻り値をキャプチャする必要がないため、コンパイラは使用するオーバーロードを決定できません。例えば。

boolean doSomething() { ... }

int doSomething() { ... }

doSomething(); // which one to call???
77
Péter Török

この質問についての興味深い側面の1つは、Java言語が戻り値の型によってのみメソッドのオーバーロードを禁止していることです。ただし、JVMではありません。

Java言語は、クラスが同じシグニチャであるが戻り値の型が異なる複数のメソッドを宣言することを禁止しているので、クラスには複数の一致するメソッドがある可能性があることに注意してください。Java仮想マシンにはありません。この仮想マシンの柔軟性の向上を利用して、さまざまな言語機能を実装できます。たとえば、共変の戻り値は、ブリッジメソッドで実装できます。ブリッジメソッドとオーバーライドされるメソッドは同じシグネチャを持ちますただし、戻り値の型が異なります。

From: Class.getMethod(String、Class ...)

32
Lukas Eder

彼らがなぜこれもサポートしていないのか疑問に思いました。確かに、戻り値を無視すると、コンパイラーはどちらが必要かを知る方法がなくなります。しかし、それはnullを渡すことで発生するのと同じあいまいさです。お気に入り:

String doSomething(String s) { ... }
String doSomething(Integer s) { ... }
...
String out=doSomething(null);

この場合、コンパイラは呼び出しが曖昧であることを報告するだけであり、次のようにnullをキャストして解決する必要があります。

String out=doSomething((String)null);

戻り値の型によるオーバーロードでも同じことができます。

String getSomething() { ... }
Integer getSomething() { ... }
...
Integer n=getSomething();

おそらく2番目の関数を呼び出します。

getSomething();

あいまいになるでしょう(そしてこの例では、副作用がない限り、おそらく役に立たないでしょうが、それは別の話です)ので、あなたは言う必要があります:

(String) getSomething();

より現実的には、おそらく:

if ((String) getSomething()==null) ...

しかし、それは簡単なケースです。単純な代入以外のことを理解するのは非常に複雑になる可能性があるため、これをサポートしたくないコンパイラライタを見ることができます。たとえば、次のことを考慮してください。

String getSomething() { ... };
Integer getSomething() { ... };
String getOtherthing() { ... };
...
if (getSomething().equals(getOtherthing())) ...

コンパイラーは、StringとIntegerの両方に同等の関数があることを理解する必要があるため、その時点ではどちらかが有効です。次に、getOtherthingがStringであり、Integer.equals(String)はありそうもないことに気づかなければならないので、おそらくライターがString.equals(String)を求めていました。実行可能ですが、その時点で、一般的なケースでは、これが獣になる可能性があることがわかり始めています。

次に、以下を追加するとします。

Integer getOtherthing() { ... };

次に、コンパイラはそのIFステートメントをどのように処理しますか?両方の関数の文字列バージョンまたは整数を使用できますが、一方の文字列ともう一方の整数は使用できません。その時点でそれを伝えるためにキャストを主張する必要があるでしょう、私は推測します。しかし、複雑さが本当に手に負えなくなってきています。

そして、コンパイラーがあなたの本当の意味を理解するのが難しい場合は、コンパイラーのようにすべての関数シグニチャーを速く検索できない別のプログラマーがどうなるか想像してみてください。

14
Jay

それはあなたが戻り値を無視する自由があるからです。

3
Tadeusz Kopec

理論的には可能ですが、C++では使用されなかったのと同じ理由で、Javaでは使用されませんでした。つまり、戻り値の型に基づくオーバーロードは、一般的に混乱を招くことがわかっています。開発者にとって、その利点は、それを実装するコストに比べてわずかであり、戻り値の型が値に割り当てられていない場合はあいまいになります。これらの理由から、戻り値型に基づくオーバーロードはサポートされていません。

その理由の1つは、ほとんどの場合、関数の戻り値の型は、このプロセスの前ではなく、関数の実行後にのみ決定できることです。したがって、関数のさまざまな戻り値のタイプに基づいて、どのオーバーロード関数を呼び出すかを決定するのに役立ちません。

メソッドのオーバーロードは、コンパイル時のポリモーフィズム技術を使用します。メソッドのオーバーライドは、実行時の多態性テクニックを使用します。

メソッドのオーバーロード:

以前の回答で述べたように、Javaは、異なる戻り値の型と同じ引数によるメソッドのオーバーロードをサポートしていません。これは、コンパイル時に使用するメソッドを決定する必要があるためです。あいまいさのため、彼らはこのようなメソッドのオーバーロード手法を設計しました。

異なる型と同じ引数でメソッドのオーバーロードが本当に必要な場合は、メソッドのオーバーライドである程度は可能です。

メソッドのオーバーライド:

メソッドのオーバーライドは、実行時の多態性テクニックを使用します。したがって、どのメソッドを実行するかはコンパイル時には決定されず、JVMによって実行時に決定されます。

共変の戻り値の型を使用すると、基本クラスと同じ引数を持つサブクラスのメソッドで異なる戻り値の型を持つことができます。

共変の戻り値の型の例:

            class BaseClass {
                BaseClass dosomething(){
                    System.out.println("Print BaseClass");
                    return this;
                }

            }

            class AnotherBaseClass extends BaseClass {
                @Override
                BaseClass dosomething(){
                    System.out.println("Print AnotherBaseClass");
                    return this;
                }
            }



            class SubClass extends AnotherBaseClass {
                @Override
                SubClass dosomething(){ /*Here SubClass is co-vairantreturn type*/ 
                    System.out.println("Print SubClass");
                    return this;
                }
                public static void main(String args[]){
                  SubClass s1 = new SubClass();
                  s1.dosomething();
                }
            }

出力:

サブクラスを印刷

0
SARIKA

呼び出し時に、パラメーターの場合のように戻り値の型を指定しないため、戻り値の型のみに基づいた関数のオーバーロードは、コンパイラーが呼び出しを区別するのを混乱させます。このパラメーター・リストは、コンパイラーが関数呼び出しを区別する唯一の方法であり、戻り値は関数の完了時に受け取られます。そのため、戻り値の型は関数のシグニチャーに寄与しません

0
Saifullah Memon