5

JungleCat を Cat のサブクラスとして持つ場合 (JungleCatCat を拡張します)、次のように言います。

JungleCat cat1 = new JungleCat();
Cat cat2 = new Cat();
Cat cat3 = new JungleCat();
JungleCat cat4 = new Cat(); //this one is illegal, right?
JungleCat cat5;

cat1cat2cat3cat4、およびのオブジェクト タイプは何cat5ですか? また、オブジェクトのインスタンス化に冗長性があるのはなぜなのか、疑問に思っています。オブジェクトをインスタンス化するときに、なぜ 2 つのオブジェクト タイプをリストする必要があるのでしょうか。

これが本当に基本的な質問である場合は申し訳ありませんが、これは私が一度だけ知りたいことであり、正当な理由のある適切な回答が必要であり、ここで期待できることを知っています (Yahoo Answers ではなく、など) :P

4

6 に答える 6

5

以下のステートメントで: -

JungleCat cat1 = new JungleCat();

次の 2 つの部分に分けることができます。

JungleCat cat1;  // This creates a reference of type `JungleCat`
cat1 = new JungleCat();   // This creates an object of type `JungleCat`.

これで、参照を作成cat1し、オブジェクトをポイントしJungleCatます。参照は、作成されたオブジェクトへのリンクにすぎないため、それらにアクセスできます。

次のようにオブジェクトを作成することもできます: -

new JungleCat();   // Will create an unnamed object

ただし、上記の場合、インスタンス化した場所でのみメソッドとプロパティを使用できます。ただし、後で、そのオブジェクトにアクセスするための参照がないため、そのプロパティにもアクセスできません。


それでは、2 番目のステートメントに進みましょう。

Cat cat = new JungleCat();

ここでは、ご想像のとおり、 type の参照と typeCat - Super ClassのオブジェクトがありますJungleCat。これを私たちは と呼んでいますPolymorphism

したがって、基本的に、任意のスーパー タイプの参照を作成し、任意のサブタイプのオブジェクトを指すようにすることができます。これは非常に簡単に理解できます。「JungleCat は Cat のみであるため、JungleCat への Cat 参照ポイントをいつでも持つことができます」。

これは逆ではありません。例: -

JungleCat ref = new Cat();

現在、これは無効です。aCatは必ずしもa ではないからJungleCatです。他の猫でもかまいません。JungleCatしたがって、オブジェクトへの参照ポイントを持つことはできませんCat


ここにあなたの実際の懸念があります: -

cat1、cat2、cat3、cat4、cat5 のオブジェクト タイプは何ですか?

cat1、..cat2はオブジェクトではなく、いくつかのオブジェクトを指す参照です。上記の説明から、それぞれの参照タイプを推測できます。

オブジェクト型は、オブジェクト作成ステートメントの RHS で使用される型です。newキーワードで使用されるタイプは、のタイプですObject。同じオブジェクト タイプを指すさまざまなタイプの参照を持つことができます。

したがって、同じオブジェクト タイプを指す と の両方cat1の参照を持つことができます。cat2

于 2012-12-14T05:28:30.357 に答える
2

cat1cat2cat3cat4、のオブジェクト タイプは何cat5ですか?

この文脈で「オブジェクトタイプ」が何を意味するのかわかりません。代わりに、宣言された型実行時の型の観点から物事を考えることをお勧めします。

  • の宣言型cat1JungleCat; の実行時型cat1JungleCat
  • の宣言型cat2Cat; の実行時型cat2Cat
  • の宣言型cat3Cat; の実行時の型cat3JungleCat
  • の宣言型cat4JungleCat; の実行時の型cat4Cat
    • はい、これは違法です。明示的なダウンキャストがないとコンパイルされません。明示的なキャストを使用すると...可能ですが、実行時に例外がスローされます。
  • の宣言型cat5JungleCat; ランタイム型はありません。

「冗長性」のポイントは、Java が静的に型付けされ、動的なディスパッチもサポートしているためです。静的型付けでは、変数に型が宣言されている必要があります。動的ディスパッチにより、実行時の型を宣言された型とは異なるものにすることができます。

たとえば、プログラムの実行中に複数のオブジェクトを同じ変数に割り当てることができます。

Cat c1 = new Cat();
c1 = new JungleCat();

の宣言された型によってc1、その変数を介して呼び出すことができるメソッドが決まります。

Cat c1 = new Cat();
c1.purr(); // compiles without error
c1 = new JungleCat();
c1.purr(); // compiles without error

同様に、その変数を介して呼び出すことができないメソッドを決定します。

JungleCat jc1 = new JungleCat();
Cat c1 = jc1;
jc1.roar(); // compiles without error - JungleCats can roar!
c1.roar(); // compile error! Cats don't roar

これにより、コンパイル時のチェックを行いながら、変数の動作を実行時の型 (多態性) によって変えることができます。

于 2012-12-14T05:28:56.760 に答える
2

オブジェクトをインスタンス化するときは、指定する必要があります

  1. 新しい変数が参照できる参照型または型(クラス)は何ですか
  2. オブジェクトを初期化するには、オブジェクトのタイプ (クラス) を指定する必要があります

したがって、基本的には JungleCat オブジェクトを作成し、それを指す参照も作成する必要があります。それを指す参照は、次の場合に Cat (JungleCat、PetCat、およびすべての猫) を指すことができます。

Cat cat3 = new JungleCat();

JungleCats のみ

JungleCat cat3 = new JungleCat();

object types of cat1, cat2, cat3, cat4, and cat5?

オブジェクト型は、代入演算子の右側からそれに代入するものになります。

JungleCat cat4 = new Cat(); //this one is illegal, right?

はい、猫はジャングルキャットであ​​る必要はありませんが(私たちが知っているのは、それが猫であるということだけです)、ジャングルキャットは確かに猫です。Cat cat= new JungleCat();それが有効な理由 です

于 2012-12-14T05:20:59.690 に答える
0

JungleCat cat4 = new Cat(); //これは違法ですよね?

はい。派生クラスの参照は、その基底クラスを指すことはできません。

cat1、cat2、cat3、cat4、cat5 のオブジェクト タイプは何ですか?

メソッドを使用getClassして知る。

オブジェクトをインスタンス化するときに 2 つのオブジェクト タイプをリストする必要がある理由。

これは と呼ばれpolymorphismます。つまり、1 つの基本クラス参照は、その派生クラスのいずれかを指すことができます。

于 2012-12-14T05:24:41.393 に答える
0

- サブクラスPolymorphismオブジェクトスーパークラスのオブジェクト参照変数に割り当てられるように動作します。

-そして、これはサブクラスであるためclass polymorphismサブクラスは同じ継承ツリーにある必要があり、サブクラスはスーパータイプである必要があります。

そう

Cat c = new JungleCat();   // Will work

しかし、

JungleCat c = new Cat();   // Won't work
于 2012-12-14T05:25:50.090 に答える
0

これは、ポリモーフィズムの背後にある基本原則です。各オブジェクトのタイプは式の左側に表示されますが、右側にあるものと同じように動作します。たとえば、次のような関数を考えてみましょう。

public static void Claw(Cat cat)
{
    cat.claw();
}

ここで、クラスが次のようなものであると仮定します。

public class Cat
{
    //...

    public void claw()
    {
        System.out.println("Cat claw");
    }
}

public class JungleCat extends Cat
{
    //...

    @Override
    public void claw()
    {
        System.out.println("Jungle cat claw");
    } 
 }

それでは、いくつかのオブジェクトをインスタンス化しましょう:

Cat c = new Cat();
Cat j = new JungleCat();

関数に渡すstatic Claw:

Claw(c); //Prints "Cat claw"
Claw(j); //Prints "Jungle cat claw"

関数を次のように変更したとします。

public static void Claw(JungleCat junglecat)
{
    junglecat.claw();
}

.Claw(c)であるため、明らかにコンパイルされませんCat。どうClaw(j)ですか?これもコンパイルされませんCat。これが実際には であることはわかっていますが、コンパイラに「わかりました。これを通常の型JungleCatのように扱ってください」と伝えています。Cat

これらの初心者の例の多くに欠けていることが多いのは、なぜ誰かがこれをやりたいのかという動機です。猫や動物などはよくない例です。より良い例として、実行しているオペレーティング システムに基づいてさまざまなことを行うことを意図したコードがあるとします。ファイルを移動するとします。で実行されている場合はLinux、ファイルを移動して/usr/bin、Windows の場合はC:\Windows\System32. したがって、次のようにインターフェースを定義します。

public interface FileMover
{
    public void move(File f);
}

public class LinuxMover implements FileMover
{
    public void move(File f)
    {
       //Move our file to /usr/bin
    }
}

public class WindowsMover implements FileMover
{
    public void move(File f)
    {
       //Move our file to C:\Windows\System32
    }
 }

さて、このコードがどのシステムで実行されるかは実行時までわかりません。そのため、実行時チェックを行い、実行時に適切なクラスをインスタンス化できます。

//Pseudocode

FileMover fm;
if(OperatingSystem == LINUX) {
    fm = new LinuxMover();
} 
else if(OperatingSystem == WINDOWS) { 
    fm = new WindowsMover();
}

fm.move();

同様に、任意の関数は単純に a を取ることができますFileMover- それらは種類を気にしません-FileMoverしたがって、異なる種類のdoSomething(WindowsFileMover m)を使用するたびに 2 つの関数定義を記述する必要はありませんdoSomething(LinuxFileMover m)doSomething(FileMover m)、正しいタイプを渡すと、「そのまま機能します」。

これはおそらく質問が必要とするよりもはるかに多くの情報ですが、うまくいけば、通常の猫と犬よりも少し具体的な方法でそのようなことが行われる理由についての直感も得られることを願っています.

于 2012-12-14T05:41:05.733 に答える