I am trying to create a generic method to create class instance by specified type parameter.
Code change conditions: * as minimum as possible changes to P1 - P3 classes its a legacy code an code below is just a prototype, ideally no changes at all to these classes.
See my code below.
trait P {
def run() : Unit = ???
}
class P1 (cfg : String ) extends P {
override def run() : Unit = {
println("1")
}
}
class P2 (cfg : String )extends P {
override def run() : Unit = {
println("2")
}
}
class P3 (cfg : String ) extends P {
override def run() : Unit = {
println("3")
}
}
def executor[T <: P](cfg: String): Unit = {
new T(cfg).run()
}
executor[P1]("someCfg")
executor[P2]("someCfg")
executor[P3]("someCfg")
Here is error I am getting:
Error:(26, 10) class type required but T found
new T(cfg).run()
^
Error:(53, 10) class type required but T found
new T(cfg).run()
^
You can do this:
import scala.reflect.ClassTag
def executor[T <: P](cfg: String)(implicit tag: ClassTag[T]): Unit = {
tag.runtimeClass.getConstructor(classOf[String]).
newInstance(cfg).asInstanceOf[T].run()
}
And use it:
executor[P1]("someCfg")
executor[P2]("someCfg")
executor[P3]("someCfg")
Reading http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html and simply searching for ClassTag
and TypeTag
will give you more information.
However, this is less safe than the solution given in the other answer: it'll fail at runtime if the class doesn't have a constructor taking String
.
Information about T
is lost in runtime due to type erasure , therefore you cannot instantiate it .
In order to satisfy your requirements with minimal changes of P1
- P3
classes you would have to pass some kind of factory function to executor
:
def executor[T <: P](cfg: String)(fct: String => T): Unit = {
fct(cfg).run()
}
In this case calling side would change to this:
executor("someCfg")(new P1(_))
executor("someCfg")(new P2(_))
executor("someCfg")(new P3(_))
with no changes to P1
- P3
classes.
Output:
1
2
3
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.