オーバーロードの挙動を調べてみた

きっかけは@kimurayaさんのつぶやき

@kimuraya オーバーロードメソッドの呼び出しの判断材料になるのは、オブジェクトの型ではなく、参照変数の型。オーバーライドメソッドの呼び出しは、オブジェクトの型に基づいて、実行時に行われるが、オーバーロードメソッドの場合は、コンパイル時に参照変数の型に基づいて、判断される。


ん?そうなの?
と気になったので、作って確認してみた。

クラス

確認用なので、ソースは適当です。

Animal.java
package sample.animal;

abstract public class Animal {
	abstract String getName();
}
Dog.java
package sample.animal;

public class Dog extends Animal {
	@Override
	String getName() {
		return "I'm dog";
	}
}
Cat.java
package sample.animal;

public class Cat extends Animal {
	@Override
	String getName() {
		return "I'm cat";
	}
}
AnimalCall.java
package sample.animal;

public class AnimalCall {
	public static void call(Animal target) {
		System.out.println("AnimalName = " + target.getName());
	}

	public static void call(Dog target) {
		System.out.println("DogName = " + target.getName());
	}

	public static void call(Cat target) {
		System.out.println("CatName = " + target.getName());
	}
}

実行してみた

JUnit使ってますが、確認用なのでAssertなし。
TDDじゃないけど、今回は見逃してw

OverLoadTest.java
package sample.animal;

import org.junit.Test;
import sample.animal.*;

public class OverLoadTest {
	@Test
	public void 親クラスの参照型を渡す() throws Exception {
		System.out.println("-- 親クラスの参照型を渡す() --");
		Animal animal1 = new Dog();
		Animal animal2 = new Cat();

		AnimalCall.call(animal1);
		AnimalCall.call(animal2);
	}

	@Test
	public void サブクラスの参照型を渡す() throws Exception {
		System.out.println("-- サブクラスの参照型を渡す() --");
		Dog dog = new Dog();
		Cat cat = new Cat();

		AnimalCall.call(dog);
		AnimalCall.call(cat);
	}
}
実行結果
-- 親クラスの参照型を渡す() --
AnimalName = I'm dog
AnimalName = I'm cat
-- サブクラスの参照型を渡す() --
DogName = I'm dog
CatName = I'm cat


おぉ、参照型で判断されてる!
上の方でインスタンスがDogでもCatでも参照型がAnimalならcall(Animal)が呼ばれてます。

今まで実際のインスタンスによって判断されてると思ってました。