これは、ポリモーフィズムの背後にある基本原則です。各オブジェクトのタイプは式の左側に表示されますが、右側にあるものと同じように動作します。たとえば、次のような関数を考えてみましょう。
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)
、正しいタイプを渡すと、「そのまま機能します」。
これはおそらく質問が必要とするよりもはるかに多くの情報ですが、うまくいけば、通常の猫と犬よりも少し具体的な方法でそのようなことが行われる理由についての直感も得られることを願っています.