2011-02-02 10 views
5

私はScalaクラスのコンストラクタ(ケースクラスまたは通常のクラスの両方が影響を受けます)のnewInstanceメソッドを呼び出そうとしています。反射を使用してスカラコンストラクタを呼び出す引数の数が間違っています

しかし、私はIllegalArgumentExceptionにヒントの間違った引数の数を実行しています。

次のことを考えてみましょう:

case class Vec2(x: Float, y: Float) 

object TestApp { 
    def main(args: Array[String]) { 
    //after some research I found the last constructor always to be the default 
    val ctor = classOf[Vec2].getConstructors.last 

    println("ctor = " + ctor) 
    println("takes parameters: " + ctor.getParameterTypes.length) 

    val params = new Array[Float](2) 

    params.update(0, 1.0f) 
    params.update(1, -1.0f) 

    println("num parameters: " + params.length) 

    println("trying to create new instance...") 
    try { 
     val x = ctor.newInstance(params) 
     println("new instance: " + x) 
    } 
    catch { 
     case ex => ex.printStackTrace 
    } 
    } 

出力を次のようになります。

ctor = public pd.test.Vec2(float,float) 
takes parameters: 2 
num parameters: 2 
trying to create new instance... 
java.lang.IllegalArgumentException: wrong number of arguments 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
    at pd.test.TestApp$.main(TestApp.scala:60) 
    at pd.test.TestApp.main(TestApp.scala) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115) 

私は一度Javaでこのような何かを経験しています。その場合、インスタンス化しようとしていたクラスが別のクラスの内部クラスであるため、Javaは暗黙的な追加パラメータを期待していました(クラスが静的として宣言されている場合はClass)。囲むクラス。

しかし、この場合、Scalaが内部的に1つを追加しない限り、包含するクラスはVec2ではありません(ただし、java.lang.Class.getEnclosingClass()が私のためにnullを返します)。

私の質問は、反射を使用してScalaクラスをインスタンス化する方法です。 Scalaのコンストラクタが暗黙的に期待する追加のパラメータはありますか?

答えて

11

newInstanceメソッドは、varargsパラメータをとります。 Scalaでは(Javaとは異なり)、配列を渡して自動的にすべての引数として扱うことはできません。それはあなたが望むなら、あなたはこのように明示的にそれを実行する必要があります。あなたは、コンストラクタの最初の引数として2つの要素を持つ配列を渡している瞬間に、何をやっている

ctor.newInstance(params:_*) 

+1

'newInstance'は' java.lang.Object'サブタイプの引数を除いているので、 'ctor.newInstance(params.map(_。asInstanceOf [Object]):_ *)'のように ' Float' –

+0

ありがとう、それが助けになった! また、Vasilに感謝します。私は、配列[AnyRef]を作成する私が作業しているジェネリッククラスでこの問題にぶつからなかった。私が投稿した例は単純化されたバージョンでした。 :) – pdinklag

+0

@Vasil Javaの場合と同様に、Scalaは基本的なプリミティブ型を持つものを自動化するので、Scalaの 'Float'は' float'または 'java.lang.Float'です。スカラのvarargsは 'Seq'を使い、Seqは消去された型なので、あなたが渡しているものは既にボックス化されており、' Object'のサブクラス化されていることが確かである。 –

関連する問題