5

なぜこれが起こっているのか理解できないという奇妙なことに直面したとき、私はコードをテストしていました。そこで、そこで起こったことの簡単な例を挙げます。

これらのクラスを検討してください

public class A {
    public void print(A a) {
        System.out.println("A");
    }
}

public class B extends A {
    public void print() {
        System.out.println("B");
    }
}

public class C extends B {
    public void print(A a) {
        System.out.println("C");
    }
}

public class E extends C {
    public void print(E e) {
        System.out.println("E");
    }
}

今私のメインメソッドでは、この種のインスタンス化があります:

    B b = new E();
    C c = new E();
    E e = new E();

これらのメソッドを呼び出して、次の出力を取得します。

    b.print(b);
    c.print(e);

出力:

C
C

2 つの説明がありますが、それぞれがこれらのメソッド呼び出しの 1 つと矛盾しています。また、私の説明はどちらも完全に間違っている可能性があるため、ここでは何も主張していません.

解説1

  • b.print(b):bのインスタンスでEあり、 にアップキャストされBます。タイプの引数を取るメソッドがありますがB、クラスによってオーバーロードされています。ただし、このメソッドへの引数は にアップキャストされるため、メソッド呼び出しは(は のスーパークラスであるため) のシグネチャと一致し、結果は有理数になります。printAEbBC.print(A a)CE

  • c.print(e): 上記と同じように考えても、ここでの出力については説明しません。cのインスタンスでEあり、 にアップキャストされCます。タイプの引数を取るメソッドがありますがC、クラスによってオーバーロードされています。しかし、上記のケースとは対照的に、このメソッドへの引数は、の署名に一致する です。したがって、この推論により、出力は E になるはずでしたが、そうではありません!printAEeE.print(E e)

解説2

ここでは、2 番目のメソッド呼び出しとその理由から始めます。

  • c.print(e):cのインスタンスでEあり、 にアップキャストされCます。type の引数を取るメソッドがありCます。このメソッドの引数は、 のインスタンスであり、 のサブクラスです。アップキャストされているので非公開です。したがって、メソッド呼び出しは の署名と一致し、出力はこのロジックによって合理的です。printAeEAE.print(E e)cC.print(A a)

  • b.print(b):bのインスタンスでEあり、 にアップキャストされBます。タイプの引数を取るメソッドがありますB(これも非表示です)。したがって、メソッド呼び出しは の署名と一致し、このロジックにより、出力は A であるはずでしたが、そうではありません。printAA.print(A a)

ここで何が起こっているのか、本当に混乱しています。誰か説明してくれませんか。

4

4 に答える 4

7

どのメソッドが呼び出されるかは、次の 2 つのステップで決定されます。

  • コンパイル時に、宣言されたインスタンス型に基づいて、オーバーロードされたメソッドのどれが使用されるかが決定されます
  • 実行時に、実際のインスタンス タイプ (ポリモーフィズム)に基づいて、オーバーライドされたメソッドのどれが使用されるかが決定されます。

    1. b.print(b); // B b = new E();

      • コンパイル時には、 の宣言された型がbisBであるため、 (またはそのスーパークラス ( ))printのインスタンスのみを受け入れることができます。つまり、次のことを意味します。BAA.print(A a)

      • b実行時に、オーバーロードされたメソッドが前のステップで選択されると、 ( )の実際の型を使用して、使用されるEバージョンが選択されます。print(A a)C.print(A a)A.print(A a)

    2. c.print(e); // C c = new E(); E e = new E();

      • コンパイル時には、 is の宣言された型とcisCの宣言された型でeあるため、これらのメソッドのみをE使用できます。A.print(A a)C.print(A a)

      • したがって、実行時には、 の実際の型eE、より具体的な (クラス階層の上位を意味する) バージョンが選択されます。C.print(A a)

于 2013-05-24T22:37:08.517 に答える
3

サンプル コードを次のように変更しました。

package com.sandbox;

public class Sandbox {
    public static void main(String[] args) {
        B b = new E();
        C c = new E();
        E e = new E();
        b.print(b); //C
        c.print(e); //C
        e.print(e); //E
        e.print(b); //C
    }


    public static class A {
        public void print(A a) {
            System.out.println("A");
        }
    }

    public static class B extends A {
        public void print() {   //doesn't override or overload anyone
            System.out.println("B");
        }
    }

    public static class C extends B {
        public void print(A a) {    //overrides "A"
            System.out.println("C");
        }
    }

    public static class E extends C {
        public void print(E e) {    //Overloads A's print
            System.out.println("E");
        }
    }
}

E のメソッドはオーバーロードされているだけなので、次のように名前を変更できます。

package com.sandbox;

public class Sandbox {
    public static void main(String[] args) {
        B b = new E();
        C c = new E();
        E e = new E();
        b.print(b); //C
        c.print(e); //C
        e.unrelatedMethod(e); //E
        e.print(b); //C
    }


    public static class A {
        public void print(A a) {
            System.out.println("A");
        }
    }

    public static class B extends A {
        public void print() {   //doesn't override or overload anyone
            System.out.println("B");
        }
    }

    public static class C extends B {
        public void print(A a) {    //overrides "A"
            System.out.println("C");
        }
    }

    public static class E extends C {
        public void unrelatedMethod(E e) {
            System.out.println("E");
        }
    }
}

そして、物事はより理にかなっています。あなたのサンプルで本当に紛らわしいのは、メソッドが同じ名前を持っていることだと思いますが、同じ方法では実際には同じではありません.

これではっきりするかどうか教えてください。これら 2 つのサンプルはまったく同じです。唯一の違いは、名前がより明確になっていることです。

于 2013-05-24T22:48:35.557 に答える