- asInstanceOf
- isInstanceOf
- classOf
の3つはscalaのキーワードというか予約語ではないです。文法上はあくまでメソッドです。けどよくよく考えると半分予約語というか、特殊な存在です。
なぜ特殊な存在かというと、これらはすべて型引数を1つだけとります。そして、実際の引数は取りません。javaでもscalaでもそうですが、受け渡す型引数によって、実行時に戻り値を変更するというのはできないはずです*1
javaを知っている人にとっては、この3つに関して、そのまま対応するものがあるのでわかりやすいはずです。以下その対応表
説明 | scala | java |
---|---|---|
一般的にいうキャスト | val str = obj.asInstanceOf[String] | String str = (String)obj; |
あるインスタンスが、その型かどうかを調べる | if(obj.isInstanceOf[String]) print("objはStringです") | if(obj instanceof String) print("objはStringです"); |
型から、その型のjava.lang.Classクラスのインスタンスを取得する | val clazz = classOf[String] | Class |
使い方だけだったら、javaわかる人はこれだけでわかると思うんですが、もうちょっと突っ込んで内部の仕組みというか、文法上どういう風に扱われているのかを調べてみます。
まずasInstanceOfとisInstanceOfですが、ライブラリのどこかのソースコード上に定義されているものではありませんAnyに定義されているものです。そして、Any自体のソースコードはありません。*2
*3
そして、classOfについてはPredefに以下のように定義されてます。
/** Return the runtime representation of a class type. This is a stub method. * The actual implementation is filled in by the compiler. */ def classOf[T]: Class[T] = null
Predefに定義されているということは、感覚的はグローバル関数のように使用できるわけです。
classOfのコメントをみると、"実際の実装はコンパイラがやるよ"みたいなことがかいてありますね。
そして、実際どうコンパイルされるのかを調べるために、お馴染みの scalac -> jad をします(`・ω・´)
object Test{ val str = "abcde" val a = str.asInstanceOf[CharSequence] val b = str.isInstanceOf[Boolean] val c = classOf[List[String]] }
import scala.ScalaObject; import scala.collection.immutable.List; public final class Test$ implements ScalaObject { public String str() { return str; } public CharSequence a() { return a; } public boolean b() { return b; } public Class c() { return c; } private Test$() { b = str() instanceof Boolean; } public static final Test$ MODULE$ = this; private final String str = "abcde"; private final CharSequence a = str(); private final boolean b; private final Class c = scala/collection/immutable/List; static { new Test$(); } }
public final class Test { public static final Class c() { return Test$.MODULE$.c(); } public static final boolean b() { return Test$.MODULE$.b(); } public static final CharSequence a() { return Test$.MODULE$.a(); } public static final String str() { return Test$.MODULE$.str(); } }
予想通りというか、大して面白く無いですね(´・ω・`)
ここからはあくまで個人的な推測です。
この3つをメソッドにした理由は、おそらく単純に、予約語を増やしたくなかったんでしょうかね?予約語でなく、メソッドとして扱っておけば、構文の解析がその分楽になるんじゃないかと。*4おそらく同じような理由で、volatile、native、transientなども、予約語ではなく*5、アノテーションになってるのではないかと思います。*6
あと、synchronizedも予約語ではなくAnyRefのメソッドという扱いですね。
*1:まちがってたら誰か突っ込んでください。実行時というのがポイントです
*2:仮想的にソースコード自体はつくろうと思えば作れますけど、コンパイラがそのソースコードもとに、Anyを他のクラスと全く同じように扱って解析し、classファイルを生成するというのが不可能です。Anyはコンパイルした後には存在しないものなので、コンパイル時のどこかのフェーズでAnyを特別扱いをしないと
*3: 2011/5/8追記 最近(2.9.0)になって、おそらくScaladoc用のために仮想的なソースコードおいてるみたいですね。NothingやNullもある
*4:javaだと、この3つが、すべて構文に組み込まれています
*6:もしこの辺の事情詳しい人いたら教えてください