2011-02-02 38 views
5

Tôi đang cố gắng gọi phương thức newInstance của một hàm tạo của lớp Scala (lớp chữ thường hoặc lớp thông thường, cả hai đều bị ảnh hưởng).Số lượng đối số sai khi gọi hàm tạo Scala bằng cách sử dụng phản chiếu

Tuy nhiên, tôi đang chạy vào một IllegalArgumentException với gợi ý sai số đối số.

xem xét như sau:

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

Đầu ra là như sau:

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) 

tôi đã trải qua một cái gì đó như thế này trong Java một lần. Trong trường hợp đó, lớp mà tôi cố gắng khởi tạo là lớp bên trong của một lớp khác, vì vậy Java mong đợi một tham số bổ sung tiềm ẩn, là đối tượng Class của lớp kèm theo (nếu lớp được khai báo là tĩnh) hoặc một thể hiện của lớp kèm theo.

Tuy nhiên, trong trường hợp này không có lớp kèm theo là Vec2, trừ khi Scala thêm một nội bộ (mặc dù, java.lang.Class.getEnclosingClass() trả về null cho tôi).

Vì vậy, câu hỏi của tôi là làm thế nào để khởi tạo các lớp Scala bằng cách sử dụng sự phản chiếu? Có bất kỳ thông số bổ sung nào mà các nhà xây dựng Scala mong đợi không?

Trả lời

11

Phương thức newInstance có tham số varargs. Trong Scala (không giống Java), bạn không thể vượt qua một mảng và nó được xử lý tự động như tất cả các đối số. Nếu đó là những gì bạn muốn, bạn cần phải làm điều đó một cách rõ ràng như thế này:

ctor.newInstance(params:_*) 

Những gì bạn đang làm hiện tại đang chuyển một mảng với 2 yếu tố làm đối số đầu tiên cho hàm tạo.

+1

'newInstance' loại bỏ các đối số của loại phụ" java.lang.Object', vì vậy bạn sẽ phải thực hiện một số thứ như 'ctor.newInstance (params.map (_. AsInstanceOf [Object]): _ *)' cho ' Float' –

+0

Cảm ơn, điều đó đã giúp bạn! Cũng nhờ Vasil. Tôi đã không chạy vào vấn đề đó với lớp chung tôi đang làm việc trên, mà tạo ra một Array [AnyRef]. Ví dụ tôi đăng là một phiên bản đơn giản. :) – pdinklag

+0

@Vasil Như với Java, Scala sẽ tự động hóa bất cứ thứ gì có một kiểu nguyên thủy cơ bản, do đó một Scala 'Float' có thể là' float' hoặc 'java.lang.Float'. Bởi vì scala varargs sử dụng 'Seq' và Seq là một kiểu bị xóa, bạn có thể chắc chắn rằng những gì bạn đang chuyển sẽ được đóng hộp và sẽ phân lớp' Object' –

Các vấn đề liên quan