2011-02-02 17 views
5

Próbuję wywołać metodę newInstance konstruktora klasy Scala (klasa przypadku lub zwykła klasa, oba mają wpływ).Niewłaściwa liczba argumentów wywołujących konstruktor Scala za pomocą refleksji

Jednak używam IllegalArgumentException z podpowiedzią złą liczbą argumentów.

Rozważmy następujący:

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 
    } 
    } 

Wyjście jest w następujący sposób:

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) 

doświadczyłem czegoś takiego w Javie raz. W tym przypadku klasa I, która próbowała utworzyć instancję, była wewnętrzną klasą innej klasy, więc Java oczekiwała niejawnego dodatkowego parametru, który był albo obiektem Class klasy otaczającej (jeśli klasa została zadeklarowana jako statyczna), albo instancją klasa otaczająca.

Jednak w tym przypadku nie ma klasy zamykającej Vec2, chyba że Scala dodaje ją wewnętrznie (jednak dla mnie zwraca null).

Moje pytanie brzmi: jak utworzyć instancje klasy Scala za pomocą refleksji? Czy są jakieś dodatkowe parametry, których konstruktory Scala oczekują pośrednio?

Odpowiedz

11

Metoda newInstance przyjmuje parametr varargs. W Scali (inaczej niż w Javie) nie można po prostu przekazać tablicy i traktować jej automatycznie jako wszystkich argumentów. Jeśli to, co chcesz, co musisz zrobić to wyraźnie tak:

ctor.newInstance(params:_*) 

Co robisz w tej chwili przechodzi tablicę z 2 elementów jako pierwszy argument do konstruktora.

+1

'newInstance' oprócz argumentów podtypu' java.lang.Object', więc wolisz zrobić coś w stylu 'ctor.newInstance (params.map (_. AsInstanceOf [Object]): _ *)' for ' Float' –

+0

Dzięki, to pomogło! Również dzięki Vasil. Nie wpadłem na ten problem z generyczną klasą, nad którą pracuję, która tworzy tablicę [AnyRef]. Zamieszczony przykład to wersja uproszczona. :) – pdinklag

+0

@Vasil Podobnie jak w przypadku Java, Scala będzie autobox wszystko, co ma podstawowy typ pierwotny, więc Scala 'Float' może być albo' float' lub 'java.lang.Float'. Ponieważ scala varargs używa 'Seq' i Seq jest wymazanym typem, możesz być pewien, że to co przechodzisz będzie już zapakowane i podklasuje' Obiekt' –

Powiązane problemy