22

私には2つのクラスがあります:

public class ClassA {
    public void method(Number n) {
        System.out.println("ClassA: " + n + " " + n.getClass());
    }
}

と:

public class ClassB extends ClassA {            
    public void method(Integer d) {
        System.out.println("ClassB: " + d + " " + d.getClass());
    }
}

しかし、私が実行すると:

ClassA a = new ClassB(); 
a.method(3);

私は得る:

ClassA: 3 class java.lang.Integer

私の質問は、なぜClassBのメソッドが使用されていないのですか? aはのインスタンスでありClassBClassB'smethod()にはIntegerパラメータがあります。

4

11 に答える 11

26

私の質問は、なぜClassBのメソッドが使用されないのですか?

違います。使用されるClassBメソッドは、から継承したのメソッドClassAです。


ここでの混乱の背後にある主な理由は、メソッドが実際にはオーバーライドされておらず、代わりにオーバーロードされているという事実にあると思います。はのIntegerサブタイプですがNumberメソッドパラメータはJavaで不変であるため、メソッドはメソッドpublic void method(Integer d)をオーバーライドしませんpublic void method(Number n)。したがって、ClassB2つの(オーバーロードされた)メソッドを持つことになります。

オーバーロードされたメソッドには静的バインディングが使用され、最も特定のパラメータータイプを持つメソッドがコンパイラーによって選択されます。public void method(Number n)しかし、この場合、コンパイラが.の代わりに選択するのはなぜですかpublic void method(Integer d)。これは、メソッドを呼び出すために使用している参照がタイプであるためClassAです。

ClassA a = new ClassB(); //instance is of ClassB (runtime info)
a.method(3);             //but the reference of type ClassA (compiletime info)

持っている唯一のメソッドClassApublic void method(Number n)、であるため、コンパイラはそれを取得します。ここで期待される引数の型はですNumberが、渡される実際の引数である整数3は、型に自動ボックス化されることを忘れないでくださいInteger。そして、それが機能する理由は、メソッド引数がJavaで共変であるためです。

さて、なぜそれが印刷されるのかは明らかだと思います

ClassA:3クラスjava.lang.Integer

于 2012-10-11T04:25:51.143 に答える
10

あなたの問題は、(継承に関する公式のJavaチュートリアルから引用されているように)次の事実から生じています。

サブクラスでは、スーパークラスから継承されたメソッドをオーバーロードできます。このようなオーバーロードされたメソッドは、スーパークラスメソッドを非表示にしたりオーバーライドしたりすることはありません。これらは、サブクラスに固有の新しいメソッドです。

詳細については、公式のJavaチュートリアルを参照してください。http: //docs.oracle.com/javase/tutorial/java/IandI/override.html

于 2012-10-11T04:10:24.947 に答える
6

aはClassA型であるため、ClassBとして宣言されていない限り、ClassBのメソッドはインスタンスaに表示されません。

ClassB a = new ClassB(); 

期待どおりの出力が得られます。数値は整数のスーパータイプです。したがって、渡したものはすべて適切なサブタイプに自動ボックス化され、ClassAのメソッドが呼び出されます。合格してみてください

a.method(3.0f) // Float
a.method(3.0) // Double
于 2012-10-11T04:33:20.457 に答える
4

引数のNumberとIntegerは、2つの異なるメソッドシグネチャを作成するためです。したがって、クラスBには、使用できる2つの異なるメソッドがあります。

于 2012-10-11T04:09:54.140 に答える
4

数値3は自動的に整数にボックス化されるためです。

以下のリンクを参照してください: http ://www.javabeat.net/articles/print.php?article_id = 31

一般的な規則:引数は、メソッドのパラメーターに一致するように暗黙的に拡張されます。あるラッパークラスから別のラッパークラスに拡張することは違法です。

于 2012-10-11T04:13:21.617 に答える
1

クリアするために、との両方でメソッドを追加しshow()ました。classAclassB

public void show() {
        System.out.println(getClass());
    }

私はこのように呼びます、

    // Case 1       
    ClassA a = new ClassB();
    a.method(3);// ClassA: 3 class java.lang.Integer
    a.show(); // class ClassB

    // Case 2       
    ClassB b = new ClassB();
    b.method(3);// ClassB: 3 class java.lang.Integer
    b.show(); // class ClassB

ここで、method(Number n)とmethod(Integer d)のシグネチャは異なります。オーバーライドしていません。過負荷です。

ただし、show()メソッドはメソッドのオーバーライドです。

ケース1の場合 、オブジェクトaでアクセスできるのはクラスAのメソッドのみです。aはclassA型であり、classBのメソッドは表示されません。 これが、classAメソッドが呼び出される理由です。ただし、オーバーライドされたメソッドであるshow()メソッドの場合、クラスBのshow()メソッドが呼び出されます。

ケース2では、ClassBがClassAを拡張するため、オブジェクトbを使用してクラスAとBの両方のメソッドにアクセスできます。

于 2012-10-11T05:10:48.097 に答える
1

2つの操作は引数(パラメーター)タイプが異なるため(サブクラスであっても)、異なると見なされます(Cとは異なり)。最初のメソッドを2番目のメソッドでオーバーライドしませんでした。代わりに、2つのメソッドを持つクラスBになりました。

 public void method(Number n)  and
 public void method(Integer n)

デフォルトでは、a.method(3)3がIntegerオブジェクトにキャストされました。これを確認するには、

a.method((Number)3);      //this would call the second method/operation.

リフレクションを使用してクラスBのメソッドを反復処理することにより、これを確認することもできます。

于 2012-10-11T04:22:33.303 に答える
1
  class ClassA
  {
     public void method( Number n )
     {
        System.out.println( "ClassA: " + n + " " + n.getClass() );
     }// void method( Number n )

  }// class ClassA

  public class ClassB
     extends
        ClassA
  {
     public void method( Integer d )
     {
        System.out.println( "ClassB: " + d + " " + d.getClass() );
     }// void method( Integer d )

     public static void main( String[] args )
     {
        ClassB b = new ClassB(); 
        ClassA a = b; 
        a.method( new Integer( 3 )); // 1. ClassA: 3 class java.lang.Integer
        b.method( new Integer( 4 )); // 2. ClassB: 4 class java.lang.Integer
        b.method( new Float( 5.6 )); // 3. ClassA: 5.6 class java.lang.Float
     }// void main( String[] args )

  }// class ClassB
  1. 2つのメソッドはオーバーロードされておらず、インスタンスはクラスaであるため、AからBへのディスパッチは発生しません。
  2. Bにはベストマッチ方式があり、それが選択されます
  3. BはFloatタイプのパラメーターを処理できないため、メソッドが選択されます
于 2012-10-11T04:33:04.513 に答える
0

あなたは次のコードを持っていました

Class A a = new ClassB(); 
a.method(3);

ただし、「a」と「3」がパラメーターとして渡され、同じコードを実行するメソッドがあるとします。

public void foo(A a, Number n)
{
    a.method(n);
}

コンパイラは、クラスAまたはクラスB(または数値または整数)のどちらを渡すかを認識していません。それでもメソッドを解決して、a.methodからの戻り値の型チェックを実行できるようにする必要があります。

于 2013-02-20T21:55:25.483 に答える
0

私はこの問題についていくつかの研究開発を行い、あなたの混乱を取り除くための解決策を考え出しました。うまくいけば、それはあなたが理解するのに役立つでしょう。

以下のコードを探してください。

class A {
    public void func(Number obj){
        System.out.println("In a func");
    }
    public void func(Integer obj){
        System.out.println("In b func");        
    }
}

class B extends A {
}

public class X {

    public static void main(String s[]){
        B b = new B();
        b.func(3);

        A a = new B();
        a.func(3);
    }
}

このコードを実行すると、次の出力が得られます:
"In b func"
"Inbfunc"

この場合、次の4つの方法があります。

  1. クラスAには、オーバーロードされたメソッドfunc(Number)[say method 1]とfunc(Integer)[saymethod2]の両方があります。
  2. クラスBにも、継承のために2つのメソッドがあります。つまり、func(Number)[say method 3]とfunc(Integer)[say method4]があります。

ここで、Bを参照してb.func(3)を呼び出すと、「メソッド3」と「メソッド4」が表示されます。これらは、派生クラスに最も適合するパラメーターを持っています。ここでは、NumberクラスとIntegerクラスの両方が引数3に適合していますが、IntegerはNumberから派生しているため、func(Integer)[method3]が呼び出されます。したがって、出力は「Inbfunc」です。

同じロジックのため、2番目の出力も「Inbメソッド」です。まず、クラスAが持っていないクラスA参照のメソッドを呼び出すことはできないことを覚えておいてください。したがって、それらのメソッドは、それが持つクラスAを参照する場合にのみ呼び出すことができます。インスタンスがクラスAであるか、サブクラスのインスタンスであるかに関係なく。

コンパイルとリンクと実行の2つの用語でそれを理解する必要があります。

現在、クラスAは両方のメソッドを持っているので、コンパイラがクラスAの参照でa.func(3)を調べると、コンパイラはクラスAの「メソッド1」と「メソッド2」を調べ、引数を持つメソッドシグネチャをバインドします。最も適合する派生クラス。「func(Integer)」もそうです。

これで、実行時にfunc(Integer)が実行され、インスタンスがクラスBであるため、クラスBから呼び出されます(実行時に、メソッドは、インスタンスがメソッドを呼び出しているクラスから実行されます)。したがって、メソッド4が呼び出されます。したがって、出力。

確かに、メソッド2が呼び出されず、メソッド4が呼び出される理由について混乱が生じるでしょう。

以下のコードを実行する場合:

class A {
    public void func(Number obj){
        System.out.println("In a func");
    }
    public void func(Integer obj){
        System.out.println("In b func");        
    }
}

class B extends A {
    public void func(Number obj){
        System.out.println("In a func of class B");
    }
    public void func(Integer obj){
        System.out.println("In b func of class B");     
    }
}

public class X {

    public static void main(String s[]){
        B b = new B();
        b.func(3);

        A a = new B();
        a.func(3);
    }
}

出力は次のようになります。
クラスBの
InbfuncクラスBのInbfunc

これで、上記の説明でこのコードを理解できます。クラスAまたはクラスBを参照してfun(3)を呼び出しました。クラスBのメソッドが呼び出されるたびに(メソッド4)。インスタンスがクラスBであるためです。ただし、クラスAにない場合(メソッド2)。メソッド4は「a.func(3)」では呼び出されません

以下のコードを見てみましょう。

class A {
    public void func(Number obj){
        System.out.println("In a func");
    }
}

class B extends A {
    public void func(Integer obj){
        System.out.println("In b func");        
    }
}
public class X {

    public static void main(String s[]){
        B b = new B();
        b.func(3);

        A a = new B();
        a.func(3);
    }
}

このプログラムの出力は次のとおりです
。InbfuncIn
afunc

今、あなたは混乱するかもしれませんが、なぜそれが異なる出力なのですか?

ここに4つの方法がないことを忘れないでください。ここに3つの方法だけがあります:

  1. クラスAのfunc(Number)
  2. クラスAから継承されたクラスBのfunc(Number)
  3. クラスBのfunc(整数)

ここで、a.fun(3)を呼び出すと、クラスAにはfunc(Integer)がなく、クラスにないクラスAを参照してメソッドを呼び出すことはできません。したがって、クラスAにはそのようなメソッドがないため、コンパイラはfunc(Integer)をバインドしません。ただし、同じコードで呼び出すことができる別のメソッドfunc(Number)があります。a.func(3)Javaのオートボクシングの概念。

したがって、a.func(3)が呼び出されると、基本的にfunc(Number)が呼び出されます。インスタンスがクラスBであるため、クラスBのメソッドfunc(Number)が呼び出されます。したがって、出力は「機能中」です。

これは非常に大きな答えですが、深く説明したので、さまざまなユースケースでの出力のさまざまな可能性を簡単に理解できます。

コーディングをお楽しみください!

于 2017-03-08T09:51:23.387 に答える
-1

オーバーロードでは、メソッドの解決は常に参照型に基づいてコンパイラによって処理されます。したがって、ランタイムオブジェクトのオーバーロードでは、object [new ClassB()]は何の役割も果たしません。したがって、あなたの場合、ClassAのメソッドが実行されました。

ClassA a = new ClassB(); 
a.method(3);
于 2017-09-05T12:32:58.180 に答える