特定の型を継承または実装しているオブジェクトに対して、何等か処理をしたい場合、判定にinstanceofを使います。
しかし、instanceofはJavaの構文であるため、動的に判定することはできません。
何とかする方法ないかなぁと調べてみると、以下のような方法がありました。Class.isInstanceかisAssignableFromを使います。
public static void main(String[] args) {
Object baseClass = new BaseClass();
Object subClass = new SubClass();
Object baseClassWithSubOthreType = new BaseClassWithSubOthreType();
Object subClassWithSubOthreType = new SubClassWithSubOthreType();
System.out.println("baseClass is Object=" + (baseClass instanceof Object));
System.out.println("baseClass is BaseClass=" + (baseClass instanceof BaseClass));
System.out.println("baseClass is SubClass=" + (baseClass instanceof SubClass));
System.out.println("baseClass is BaseOthreType=" + (baseClass instanceof BaseOthreType));
System.out.println("subClass is Object=" + (subClass instanceof Object));
System.out.println("subClass is BaseClass=" + (subClass instanceof BaseClass));
System.out.println("subClass is SubClass=" + (subClass instanceof SubClass));
System.out.println("subClass is BaseOthreType=" + (subClass instanceof BaseOthreType));
System.out.println("baseClassWithSubOthreType is Object=" + (baseClassWithSubOthreType instanceof Object));
System.out.println("baseClassWithSubOthreType is BaseClass=" + (baseClassWithSubOthreType instanceof BaseClass));
System.out.println("baseClassWithSubOthreType is SubClass=" + (baseClassWithSubOthreType instanceof SubClass));
System.out.println("baseClassWithSubOthreType is BaseOthreType=" + (baseClassWithSubOthreType instanceof BaseOthreType));
System.out.println("subClassWithSubOthreType is Object=" + (subClassWithSubOthreType instanceof Object));
System.out.println("subClassWithSubOthreType is BaseClass=" + (subClassWithSubOthreType instanceof BaseClass));
System.out.println("subClassWithSubOthreType is SubClass=" + (subClassWithSubOthreType instanceof SubClass));
System.out.println("subClassWithSubOthreType is BaseOthreType=" + (subClassWithSubOthreType instanceof BaseOthreType));
System.out.println("-----------");
System.out.println("baseClass is Object=" + Object.class.isInstance(baseClass));
System.out.println("baseClass is BaseClass=" + BaseClass.class.isInstance(baseClass));
System.out.println("baseClass is SubClass=" + SubClass.class.isInstance(baseClass));
System.out.println("baseClass is BaseOthreType=" + BaseOthreType.class.isInstance(baseClass));
System.out.println("subClass is Object=" + Object.class.isInstance(subClass));
System.out.println("subClass is BaseClass=" + BaseClass.class.isInstance(subClass));
System.out.println("subClass is SubClass=" + SubClass.class.isInstance(subClass));
System.out.println("subClass is BaseOthreType=" + BaseOthreType.class.isInstance(subClass));
System.out.println("baseClassWithSubOthreType is Object=" + (Object.class.isInstance(baseClassWithSubOthreType)));
System.out.println("baseClassWithSubOthreType is BaseClass=" + (BaseClass.class.isInstance(baseClassWithSubOthreType)));
System.out.println("baseClassWithSubOthreType is SubClass=" + (SubClass.class.isInstance(baseClassWithSubOthreType)));
System.out.println("baseClassWithSubOthreType is BaseOthreType=" + BaseOthreType.class.isInstance(baseClassWithSubOthreType));
System.out.println("subClassWithSubOthreType is Object=" + Object.class.isInstance(subClassWithSubOthreType));
System.out.println("subClassWithSubOthreType is BaseClass=" + BaseClass.class.isInstance(subClassWithSubOthreType));
System.out.println("subClassWithSubOthreType is SubClass=" + SubClass.class.isInstance(subClassWithSubOthreType));
System.out.println("subClassWithSubOthreType is BaseOthreType=" + BaseOthreType.class.isInstance(subClassWithSubOthreType));
System.out.println("-----------");
System.out.println("baseClass is Object=" + Object.class.isAssignableFrom(baseClass.getClass()));
System.out.println("baseClass is BaseClass=" + BaseClass.class.isAssignableFrom(baseClass.getClass()));
System.out.println("baseClass is SubClass=" + SubClass.class.isAssignableFrom(baseClass.getClass()));
System.out.println("baseClass is BaseOthreType=" + BaseOthreType.class.isAssignableFrom(baseClass.getClass()));
System.out.println("subClass is Object=" + Object.class.isAssignableFrom(subClass.getClass()));
System.out.println("subClass is BaseClass=" + BaseClass.class.isAssignableFrom(subClass.getClass()));
System.out.println("subClass is SubClass=" + SubClass.class.isAssignableFrom(subClass.getClass()));
System.out.println("subClass is BaseOthreType=" + BaseOthreType.class.isAssignableFrom(subClass.getClass()));
System.out.println("baseClassWithSubOthreType is Object=" + (Object.class.isAssignableFrom(baseClassWithSubOthreType.getClass())));
System.out.println("baseClassWithSubOthreType is BaseClass=" + (BaseClass.class.isAssignableFrom(baseClassWithSubOthreType.getClass())));
System.out.println("baseClassWithSubOthreType is SubClass=" + (SubClass.class.isAssignableFrom(baseClassWithSubOthreType.getClass())));
System.out.println("baseClassWithSubOthreType is BaseOthreType=" + BaseOthreType.class.isAssignableFrom(baseClassWithSubOthreType.getClass()));
System.out.println("subClassWithSubOthreType is Object=" + Object.class.isAssignableFrom(subClassWithSubOthreType.getClass()));
System.out.println("subClassWithSubOthreType is BaseClass=" + BaseClass.class.isAssignableFrom(subClassWithSubOthreType.getClass()));
System.out.println("subClassWithSubOthreType is SubClass=" + SubClass.class.isAssignableFrom(subClassWithSubOthreType.getClass()));
System.out.println("subClassWithSubOthreType is BaseOthreType=" + BaseOthreType.class.isAssignableFrom(subClassWithSubOthreType.getClass()));
}
static class BaseClass {
}
static class SubClass extends BaseClass {
}
static class BaseClassWithSubOthreType implements SubOthreType {
}
static class SubClassWithSubOthreType extends SubClass implements SubOthreType {
}
interface BaseOthreType {
}
interface SubOthreType extends BaseOthreType {
}
■出力結果(どれも同じ結果が出ます)
baseClass is Object=true
baseClass is BaseClass=true
baseClass is SubClass=false
baseClass is BaseOthreType=false
subClass is Object=true
subClass is BaseClass=true
subClass is SubClass=true
subClass is BaseOthreType=false
baseClassWithSubOthreType is Object=true
baseClassWithSubOthreType is BaseClass=false
baseClassWithSubOthreType is SubClass=false
baseClassWithSubOthreType is BaseOthreType=true
subClassWithSubOthreType is Object=true
subClassWithSubOthreType is BaseClass=true
subClassWithSubOthreType is SubClass=true
subClassWithSubOthreType is BaseOthreType=true
-----------
baseClass is Object=true
baseClass is BaseClass=true
baseClass is SubClass=false
baseClass is BaseOthreType=false
subClass is Object=true
subClass is BaseClass=true
subClass is SubClass=true
subClass is BaseOthreType=false
baseClassWithSubOthreType is Object=true
baseClassWithSubOthreType is BaseClass=false
baseClassWithSubOthreType is SubClass=false
baseClassWithSubOthreType is BaseOthreType=true
subClassWithSubOthreType is Object=true
subClassWithSubOthreType is BaseClass=true
subClassWithSubOthreType is SubClass=true
subClassWithSubOthreType is BaseOthreType=true
-----------
baseClass is Object=true
baseClass is BaseClass=true
baseClass is SubClass=false
baseClass is BaseOthreType=false
subClass is Object=true
subClass is BaseClass=true
subClass is SubClass=true
subClass is BaseOthreType=false
baseClassWithSubOthreType is Object=true
baseClassWithSubOthreType is BaseClass=false
baseClassWithSubOthreType is SubClass=false
baseClassWithSubOthreType is BaseOthreType=true
subClassWithSubOthreType is Object=true
subClassWithSubOthreType is BaseClass=true
subClassWithSubOthreType is SubClass=true
subClassWithSubOthreType is BaseOthreType=true
・・・そもそもタイプ別で分岐しないといけないというのは設計が悪い。というケースが多いのかなぁと思います。
しかし、実装レベルで楽をするために。というのはありかなぁと思います。
たとえば、例外発生時のエラーメッセージの判定を一括して行う処理を実装する場合、これをMap<Exceptionのラッパー,String>で処理できるとずいぶんすっきりすると思います。
キーになる情報のhashcode()を工夫すれば、楽に実装できるような気がします。
instanceofだとif文たくさんになる図が目に浮かびますね。
しかし、この2つは、何が違うんでしょう?リファレンスを見ると、
- isInstanceは、Java 言語の instanceof 演算子と動的に等価
- isAssignableFromは、型として等しいか。プリミティブのタイプも判定できる
ということらしいです。
・・・じゃあ、相互互換ってどうなんだろう?ということでやってみました。コードと結果は以下の通り
System.out.println("Integer isInstance int = " + int.class.isInstance(new Integer(1)));
System.out.println("int isInstance Integer = " + Integer.class.isInstance(1));
System.out.println("Integer isAssignableFrom int = " + int.class.isAssignableFrom(Integer.class));
System.out.println("int isAssignableFrom Integer = " + Integer.class.isAssignableFrom(int.class));
--以下出力結果
Integer isInstance int = false
int isInstance Integer = true
Integer isAssignableFrom int = false
int isAssignableFrom Integer = false
Class.isInstanceでは、双方向でtrueを予想していたのですが、Integerとintは互換があり、逆は互換がない。っていう結果になりました。
Class.isAssignableFromに関しては、両方false。理由がよくわからない。。。