web-dev-qa-db-ja.com

スーパークラスオブジェクトでサブクラスのメソッドを呼び出すことは可能ですか?

動物は犬のスーパークラスであり、犬には樹皮と呼ばれる方法があります

public void bark()
{
    System.out.println("woof");
}

次のことを考慮してください。

Animal a = new Dog();
if (a instanceof Dog){
    a.bark();
}

何が起こるか?

  1. 割り当ては許可されていません
  2. 樹皮への呼び出しが許可され、実行時に「woof」が出力されます
  3. 樹皮への呼び出しは許可されますが、何も印刷されません
  4. barkを呼び出すと、コンパイル時エラーが発生します
  5. 樹皮を呼び出すと、実行時エラーが発生します

オブジェクトが犬であるかどうかを確認しているときに、2と言いました。 dogはbarkメソッドを含むクラスであるため、そうである場合は、それを呼び出して出力します:s

私の理解はここで正しいですか?

16
roberto

Animalにはbarkというメソッドがないため、これはコンパイルされません。このように考えると、すべての犬は動物ですが、すべての動物が犬であるとは限りません。すべての犬が吠えますが、すべての動物が吠えるわけではありません。

32
Sam Trost

いいえ-答えは;

4)barkを呼び出すと、コンパイル時エラーが発生します

樹皮メソッドは、割り当てられたタイプの動物のメソッドとして定義されていないため、コンパイル時の問題が発生します。これはキャストすることで解決できます。

((Dog)a).bark();
27
simon622

キーは次の行にあります。

_Animal a = new Dog();
_

Dogの新しいインスタンスが作成されましたが、その参照はaによるものであり、タイプAnimalであると宣言されています。したがって、aを参照すると、_new Dog_はAnimalとして処理されます。

したがって、Animalbarkメソッドがない限り、次の行でコンパイラエラーが発生します。

_a.bark();
_

aDogのインスタンスであるかどうかを確認するためにテストされ、_a instanceof Dog_が実際にtrueを返す場合でも、変数aはまだタイプはAnimalであるため、ifステートメント内のブロックは引き続きaAnimalとして処理します。

これは 静的に型付けされた言語 の機能であり、変数には事前に型が割り当てられ、コンパイル時に型が一致するかどうかがチェックされます。このコードが 動的に型付けされた言語 で実行され、実行時に型がチェックされる場合、次のようなことが許可される可能性があります。

_var a = new Dog();
if (a instanceof Dog)
    a.bark();
_

a.bark()は、インスタンスがDogの場合にのみ実行されることが保証されているため、barkの呼び出しは常に機能します。ただし、Javaは静的に型指定された言語であるため、このタイプのコードは許可されていません。

11
coobird

Head First Java では、参照にテレビのリモコンの非常に優れたアナロジーを使用し、参照が指すオブジェクト。リモコンにオン、オフ、チャンネルの上下、音量の上下のボタン(メソッド)しかない場合は、テレビの優れた機能は関係ありません。あなたはまだあなたのリモコンからそれらのいくつかの基本的なことをすることができるだけです。たとえば、リモコンにミュートボタンがない場合、テレビをミュートすることはできません。

動物リファレンスは、動物の方法についてのみ知っています。基になるオブジェクトが他にどのようなメソッドを持っているかは関係ありません。Animal参照からそれらにアクセスすることはできません。

5
Bill the Lizard

それは4です。一般的な動物(コードが言うことです)に吠えるように頼むことはできません。あなたが同じように簡単に言うことができたので

Animal a = new Cat();

樹皮の線には、あなたがそうしなかったことを知る方法がありません。

4
Carl Manaster

スーパークラスオブジェクトからサブクラスメソッドを出力するというアイデアの場合、これは機能します。

Animal a = new Dog(); if (a instanceof Dog){ a.bark(); }の代わりに

Animal a = new Dog();

if (a instanceof Dog){ 
    Dog d = (Dog) a; 
    d.bark();
}  

これにより、スーパークラスがサブクラスにキャストされ、出力されます。悪いデザインですが、どの子クラスオブジェクトが動的にポイントしているのかを知る1つの方法です。

4
gayathri

Java(私が知っている言語のみ)では、空のメソッドを作成してスーパークラスで呼び出すことができます。次に、サブクラスでそれをオーバーライドして、やりたいことを何でもすることができます。このようにして、スーパークラスはそのサブクラスのメソッドを呼び出します。

public class Test {
    public static void main(String[] args){
        Snake S = new Snake();
        Dog d = new Dog();
    }
}


class Animal{ //Super Class
    public Animal(){
        bark(); //calls bark when a new animal is created
    }
    public void bark(){
        System.out.println("this animal can't bark");
    }
}



class Dog extends Animal{ //Subclass 1
    @Override
    public void bark(){
        System.out.println("Woof");
    }
}



class Snake extends Animal{//Subclass 2
    public void tss(){
    }
}

このコードは、Snakeのオブジェクトを呼び出してから、Dogのオブジェクトを呼び出します。これをコンソールに書き込みます。

this animal can't bark
Woof

Snakeにはbarkメソッドがないため、スーパークラスのメソッドが呼び出されます。最初の行をコンソールに書き込みます。 Dogには樹皮メソッドがあるため、スーパークラスが代わりにそれを呼び出します。 2行目をコンソールに書き込みます。

2
WVrock

参考までに、これは良いデザインではありません。

この形式のコードがあるときはいつでも:

if (x instanceof SomeClass)
{
   x.SomeMethod();
}

あなたは型システムを乱用しています。これはクラスを使用する方法ではなく、保守可能なオブジェクト指向コードを作成する方法でもありません。もろいです。複雑です。悪いです。

基本クラスでテンプレートメソッドを作成できますが、基本クラスに存在し、サブクラスでオーバーライドされるメソッドを呼び出す必要があります。

2
Wedge

"オブジェクトが犬であるかどうかを確認しているときに2と言いました。犬は樹皮メソッドを含むクラスであるため、そうである場合は呼び出して:sを出力します。

あなたの論理的根拠は正しいですが、それはそれが機能する方法ではありません。

Javaは静的型付き言語です。つまり、オブジェクトが応答する可能性のあるメソッドの有効性は、コンパイル時で検証されます。

あなたはチェックを考えるかもしれません:

if( a instanceof Dog ) 

するだろうが、実際にはそうではない。コンパイラが行うことは、宣言された型(この場合はAnimal)の「インターフェース」に対してチェックすることです。 「インターフェース」は、Animalクラスで宣言されたメソッドで構成されています。

bark()メソッドがスーパークラスで定義されていない場合Animalコンパイラは次のように言います:「ねえ、それはしません作業"。

これは、コーディング中にタイプミスを「時々」行うために役立ちます(たとえば、代わりにbarck()と入力します)。

コンパイラがこれについて警告しない場合は、「実行時」にそれを見つける必要があり、常に明確なメッセージが表示されるとは限りません(たとえば、IEのjavascriptは「予期しないオブジェクト」 ")

それでも、Javaのような静的型付き言語を使用すると、呼び出しを強制できます。この場合、「キャスト」演算子()を使用しています。

このような

1. Animal a = new Dog();
2.  if (a instanceof Dog){
3.     Dog imADog = ( Dog ) a;
4.     imADog.bark();
5. }

3行目では、Dogタイプに「キャスト」しているため、コンパイラーは樹皮が有効なメッセージであるかどうかを確認できます。

これは、「私はここのプログラマーです。私が何をしているのか知っています」とコンパイラーに指示するものです。そして、コンパイラは、チェック、OK、犬、メッセージbark()を受信でき、続行します。ただし、実行時に動物が犬でない場合は、実行時の例外が発生します。

キャストは次のように省略できます。

if( a instanceof Dog ) {
   ((Dog)a).bark();  
}

それが実行されます。

したがって、正解は4: "樹皮を呼び出すとコンパイル時エラーが発生します"

これがお役に立てば幸いです。

1
OscarRyz