2009-10-29 46 views
7

Tôi đang cố gắng tìm ra cách khởi tạo đối tượng lớp chữ với sự phản ánh. Có hỗ trợ cho việc này không? Gần nhất tôi đã đến là nhìn vào scala.reflect.Invocation, nhưng điều này có vẻ nhiều hơn để thực hiện các phương thức là một phần của một đối tượng.đối tượng khởi tạo với sự phản chiếu bằng cách sử dụng đối số hàm dựng

case class MyClass(id:Long, name:String) 

def instantiate[T](className:String)(args:Any*) : T = { //your code here } 

Gần với API tôi đang tìm kiếm.

Mọi trợ giúp sẽ được đánh giá cao.

+0

Sự phản ánh liên quan ở đây không liên quan gì đến các trường hợp cụ thể. Bạn chỉ cần một số phản ánh để định kiểu args. Nếu tôi sai, bạn có thể xây dựng được không? – HRJ

+0

Bạn là đúng, ngoại trừ một phần của mục tiêu là để có thể viết các trường hợp đơn giản và sau đó sử dụng một phương pháp như thế này để khởi tạo/sửa đổi chúng. – justin

Trả lời

18
scala> case class Foo(id:Long, name:String) 
defined class Foo 

scala> val constructor = classOf[Foo].getConstructors()(0) 
constructor: java.lang.reflect.Constructor[_] = public Foo(long,java.lang.String) 

scala> val args = Array[AnyRef](new java.lang.Integer(1), "Foobar") 
args: Array[AnyRef] = Array(1, Foobar) 

scala> val instance = constructor.newInstance(args:_*).asInstanceOf[Foo] 
instance: Foo = Foo(1,Foobar) 

scala> instance.id 
res12: Long = 1 

scala> instance.name 
res13: String = Foobar 

scala> instance.getClass 
res14: java.lang.Class[_] = class Foo 

Hiện tại không có nhiều hỗ trợ phản chiếu trong Scala. Nhưng bạn có thể quay lại Java Reflection API thứ. Nhưng có một số trở ngại:

  • Bạn phải tạo một Array[AnyRef] và hộp "loại nguyên thủy" của mình trong các lớp wrapper (java.lang.Integer, java.lang.Character, java.lang.Double, ...)

  • newInstance(Object ... args) được một mảng varargs của Object, vì vậy bạn nên cung cấp cho loại inferer một gợi ý với :_*

  • newInstance(...) trả về một Object vì vậy bạn phải cast nó trở lại với asInstanceOf[T]

Gần nhất tôi có thể nhận được chức năng instantiate của bạn là thế này:

def instantiate(clazz: java.lang.Class[_])(args:AnyRef*): AnyRef = { 
    val constructor = clazz.getConstructors()(0) 
    return constructor.newInstance(args:_*).asInstanceOf[AnyRef] 
} 

val instance = instantiate(classOf[MyClass])(new java.lang.Integer(42), "foo") 
println(instance)   // prints: MyClass(42,foo) 
println(instance.getClass) // prints: class MyClass 

Bạn không thể có được lớp get từ một kiểu generic. Java xóa nó (loại tẩy xoá).

Edit: 20 Tháng Chín 2012

Ba năm trôi qua, các phương pháp instantiate có thể được cải thiện để trả về một đối tượng đã gõ đúng.

Xem http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html

+0

làm thế nào chúng ta có thể sửa đổi chương trình trên nếu chúng ta có đầu vào như là giá trị chuỗi của trường hợp lớp, ví dụ trong trường hợp trên nói rằng chúng ta có đầu vào cho chương trình của chúng ta như là giá trị chuỗi của trường hợp lớp là "Foo". của trường hợp lớp – Aamir

+0

@Aamir Còn về 'java.lang.Class.forName (" Foo ")' thì sao? –

2

Đây là những gì tôi đã kết thúc với cho đến nay, tôi muốn không phải đối phó trực tiếp với AnyRef nếu có thể. Vì vậy, nếu bất cứ ai biết một cách để có được xung quanh mà tôi đánh giá cao sự giúp đỡ.

case class MyClass(id:Long,name:String) 

def instantiate[T](classArgs: List[AnyRef])(implicit m : Manifest[T]) : T ={ 
     val constructor = m.erasure.getConstructors()(0) 
     constructor.newInstance(classArgs:_*).asInstanceOf[T] 
    } 

val list = List[AnyRef](new java.lang.Long(1),"a name") 
val result = instantiate[MyClass](list) 
println(result.id) 
+0

Điều này có thực sự cho phép bạn khởi tạo một lớp mà bạn không biết về thời gian chạy không? Không phải là tham số kiểu cho quy tắc phương thức khởi tạo không? –

+0

Tìm ra đoạn này chỉ là một phần nhỏ trong những gì tôi đang làm.Tôi chỉ đang thử nghiệm các ý tưởng về việc sử dụng các đối tượng bất biến trong lớp truy cập dữ liệu. – justin

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