7

この質問が主に意見に基づいている場合は申し訳ありませんが、そうではなく、選択には十分な理由があると感じています。では、例を示します。申し訳ありませんが、非常に長いですが、非常に簡単です。

インターフェース:

public interface Shape
{
    double area ();
}

クラス 1 の実装:

import static java.lang.Math.PI;

public class Circle implements Shape
{
    private double radius;

    public Circle(double radius)
    {
        this.radius = radius;
    }

    public double area()
    {
        return PI*radius*radius;
    }
}

クラス 2 の実装:

public class Square implements Shape
{
    private double size;

    public Square(double sideLength)
    {
        size = sideLength;
    }

    public double area()
    {
        return size*size;
    }   
}

運転者:

Shape[] shapes = new Shape[]{new Circle (5.3), new Square (2.4)};

System.out.println(shapes[0].area()); //prints 88.247...
System.out.println(shapes[1].area()); //prints 5.76

これはand.area()によってオーバーライドされるため機能します。さて、ここから私の質問が本当に始まります。ドライバーに次のメソッドがあるとします。CircleSquare

public static void whatIs(Shape s)
{
    System.out.println("Shape");
}

public static void whatIs(Circle s)
{
    System.out.println("Circle");
}

public static void whatIs(Square s)
{
    System.out.println("Square");
}

呼び出す場合:

whatIs(shapes[0]); //prints "Shape"
whatIs(shapes[1]); //prints "Shape"

これは、Java がオブジェクトを and ではなく s として解釈するために発生しShapeます。もちろん、次の方法で目的の結果を得ることができます。CircleSquare

if (shapes[0] instanceof Circle)
{
    whatIs((Circle) shapes[0]); //prints "Circle"
}
if (shapes[1] instanceof Square)
{
    whatIs((Square) shapes[1]); //prints "Square"
}

背景がわかったので、私の質問は次のとおりです。「Shape」を出力する
ようなコンパイラ/言語設計に貢献した理由は何ですか? whatIs(shapes[0]);同様に、なぜ Java コンパイラは、関連するオブジェクトのオーバーライドされたメソッドを正確に区別できるのに、オーバーロードされたメソッドを正確に区別できないのでしょうか? より具体的には、ドライバーがアクセスできる唯一のメソッドが次の場合:

public static void whatIs(Circle s)
{
    System.out.println("Circle");
}
public static void whatIs(Square s)
{
    System.out.println("Square");
}

そして私たちは電話をかけようとします、

whatIs(shapes[0]);
whatIs(shapes[1]);

次のことを示す 2 つのエラー ( に対して 1 つと に対してSquare1 つCircle) が表示されます。

  • メソッド Driver.whatIs(Square) は適用されません
    • 実引数 Shape はメソッド呼び出し変換で Square に変換できません

繰り返しになりますが、ここまでで要点を説明しましたが、なぜ Java はこのような状況を処理できないのでしょうか? 同様に、これは効率の問題のために行われているのでしょうか、設計上の決定のために不可能なのですか、これは何らかの理由で悪い習慣なのですか?

4

5 に答える 5

5

Java はオブジェクト指向の機能を備えており、ポリモーフィズムをサポートしているため、呼び出すareaarea特定のインスタンスのメソッドが何であれ呼び出されます。これは実行時に決定されます。

ただし、このポリモーフィズムはオーバーロードされたメソッドではサポートされていません。Java 言語仕様のセクション 8.4.9 では、次のことが説明されています。

メソッドが呼び出されると (§15.12)、呼び出されるメソッドのシグネチャを決定するために、コンパイル時に実際の引数 (および明示的な型引数) の数と引数のコンパイル時の型が使用されます ( §15.12.2)。呼び出されるメソッドがインスタンス メソッドである場合、呼び出される実際のメソッドは、動的メソッド ルックアップ (§15.12.4) を使用して、実行時に決定されます。

つまり、オーバーロードされたメソッドでは、ポリモーフィズムのように実行時にではなく、コンパイル時に変数の型を使用してメソッドが選択されます。

于 2013-08-09T17:23:03.817 に答える
2

いずれかのメソッドへのディスパッチはwhatIs、コンパイル時にコンパイラによって決定されます。いずれかのメソッドの呼び出しは、area参照されるオブジェクトの実際のクラスに基づいて、実行時に決定されます。

于 2013-08-09T17:22:57.043 に答える
1

まあ、ばかげた答えとして、この方法で whatIs 関数を正常に動作させることができます(型チェックなし)

class Shape{
  public abstract String whatIs();
}

class Square{
  public String whatIs(){ return "Square"; }
}
class Circle{
  public String whatIs(){ return "Circle"; }
}

そして、このように呼び出します

Shape square = new Square();
Shape circle = new Circle();

System.out.println(square.whatIs()) //prints 'square'
System.out.println(circle.whatIs()) //prints 'circle

あなたが尋ねた質問に対する答えではありません... しかし、私は抵抗できませんでした。

于 2013-08-09T17:51:27.810 に答える
1

Q: Java コンパイラは、関連するオブジェクトのオーバーライドされたメソッドを正確に区別できるのに、オーバーロードされたメソッドを正確に区別できないのはなぜですか? Java がこのような状況を処理できないのはなぜですか?

A: 質問が逆になっていますね。

Javaでは、「オーバーロード」と「オーバーライド」を区別できます。

それはあなたが何を意味するのかを再推測しようとはしません。どちらかを使用する選択肢を提供します。

于 2013-08-09T17:24:44.450 に答える