S-JIS[2010-12-30/2015-09-22] 変更履歴
Scalaのリフレクション関連のクラスは、scala.reflectパッケージに入っている。
|
|
JavaでClassクラスが取得できるのと同様に、Scalaでも取得できる。
Scala | Java相当 | 備考 |
---|---|---|
val c = classOf[クラス名] |
Class c = クラス名.class; |
|
val c = obj.getClass() val c = obj.getClass |
Class c = obj.getClass(); |
AnyRefの派生クラスで使用可能。 objがnullだとNullPointException。 |
obj.isInstanceOf[クラス名] |
obj instanceof クラス名 |
objがnullでも使用可能。 |
val o = obj.asInstanceOf[クラス名] |
クラス名 o = (クラス名)obj; |
objがnullでも使用可能。 |
ちなみに、isInstanceOfやasInstanceOfが長めでくどいメソッド名になっているのは、「なるべく使うな」という意思表示らしい。
→isInstanceOfで判定してからasInstanceOfでキャストするなら、match式の方が便利
Scalaでは記号入りの名前(メソッド名やフィールド名)を付けることが出来る。[2011-04-16]
その際、コンパイルされたJavaコードでは、Javaで使える文字に変換される。例えば「name_=」は「name_$eq」となる。
Scala記号 | Java記号 |
---|---|
~ |
$tilde |
= |
$eq |
< |
$less |
> |
$greater |
! |
$bang |
# |
$hash |
% |
$percent |
^ |
$up |
& |
$amp |
| |
$bar |
Scala記号 | Java記号 |
---|---|
* |
$times |
/ |
$div |
+ |
$plus |
- |
$minus |
: |
$colon |
; |
$u003B |
\ |
$bslash |
? |
$qmark |
@ |
$at |
※ピリオド「.
」やカンマ「,
」といった文字(文法上使用されているので、通常は識別子として使用しない文字だと思われる)は、Unicodeの文字コード「$u002E」や「$002C」になるようだ。[2015-09-22]
これらの変換を行うのに、NameTransformerオブジェクトが使える。
scala> import scala.reflect.NameTransformer import scala.reflect.NameTransformer scala> NameTransformer.encode("name_=") res1: String = name_$eq scala> NameTransformer.decode("name_$eq") res2: String = name_=
参考: kmizuさんのscala_tips
ケースクラスを作ると、コンパニオンオブジェクトが作られる。[2011-03-09]
「classOf[クラス名]」で取れるのはクラスの方。オブジェクトはコンパイルしてJavaのクラス化すると「$」付きのクラス名になる。
scala> case class C(a:Int, b:String)
defined class C
scala> classOf[C]
res0: java.lang.Class[C] = class C
scala> classOf[C$]
<console>:21: error: not found: type C$
classOf[C$]
^
scala> Class.forName(classOf[C].getName + "$")
res1: java.lang.Class[_] = class C$
オブジェクトはVM内で唯一のインスタンスなので、このClassからインスタンス生成(newInstance())することは出来ない。
と思ったのだが。
フィールド0個 | フィールド1個 | フィールド2個 | |
---|---|---|---|
ケースクラス |
case class C0 |
case class C1(a: String) |
case class C2(a: Int, b:Int) |
オブジェクト のクラス |
scala> val c0 = Class.forName(classOf[C0].getName+"$") c0: java.lang.Class[_] = class C0$ |
scala> val c1 = Class.forName(classOf[C1].getName+"$") c1: java.lang.Class[_] = class C1$ |
scala> val c2 = Class.forName(classOf[C2].getName+"$") c2: java.lang.Class[_] = class C2$ |
インスタンス生成 |
scala> val n0 = c0.newInstance n0: Any = <function0> |
scala> val n1 = c1.newInstance n1: Any = <function1> |
scala> val n2 = c2.newInstance n2: Any = <function2> |
キャスト |
scala> val f0 = n0.asInstanceOf[Function0[C0]] f0: () => C0 = <function0> |
scala> val f1 = n1.asInstanceOf[Function1[String,C1]] f1: (String) => C1 = <function1> |
scala> val f2 = n2.asInstanceOf[Function2[Int,Int,C2]] f2: (Int, Int) => C2 = <function2> |
apply()実行 |
scala> f0() res33: C0 = C0() |
scala> f1("abc") res34: C1 = C1(abc) |
scala> f2(123, 456) res35: C2 = C2(123,456) |
newInstanceでFunctionが返って来ているので何だろうと思って実行(apply)してみたら、ケースクラスのインスタンスが生成できている。
ということは、オブジェクトのnewInstanceが成功しているってことか(苦笑)
ケースクラスのコンパニオンオブジェクトはFunctionを継承していて、クラス自体はfinalだけれどもコンストラクターは特に定義されていない(つまりデフォルトのコンストラクターとしてpublicで引数なしのコンストラクターが存在する)から、newInstanceが実行できてしまうようだ。
public final class C0$ extends AbstractFunction0 implements ScalaObject, Serializable { //jad 〜 public static final C0$ MODULE$ = this; static { new C0$(); } }
で、どうもMODULE$というフィールドでインスタンスを保持しているようで、これがpublicだから、こっちから取る方が良い気がする。
scala> val m1 = c1.getField("MODULE$").get(null).asInstanceOf[Function1[String, C1]] m1: (String) => C1 = <function1> scala> m1("abc") res37: C1 = C1(abc)
そもそもリフレクションでコンパニオンオブジェクトを取得しようとすること自体が良くない気もするけど(爆)
ちなみに、SeqやMap等のコレクション(Traversable)には、コンパニオンオブジェクトを取得するメソッドが用意されている。[2011-10-01]
val seq = Seq[Any]() val obj = seq.companion