I have a generic method which a generic type parameter T
which is a subclass of MyClass
. Inside that method, I want to create e new instance of T
, how can I do that?
This doesn't work (because of type erasure):
object Demo extends App {
def myMethod[T <: MyClass](): Unit = {
val t = new T // gives error: class type required by T found
}
myMethod[MySubclassA]()
}
abstract class MyClass
class MySubclassA extends MyClass
class MySubclassB extends MyClass
It fails to work, but not (primarily) because of type erasure, but because your definition should make sense for all T
which satisfy the type bounds, and new T
doesn't. E.g. T
can be MyClass
or an abstract subclass, or a subclass without a parameter-less constructor, or a trait (traits can extend classes), or...
If a runtime error is good enough, you can go with Sergey Lagutin's solution. But more reasonable for most cases would be to pass some way to create a T
to myMethod
. Possibly as an implicit argument, e.g.
class Factory[T](f: () => T) {
def make(): T = f()
}
object Factory {
implicit val MySubclassAFactory =
new Factory(() => new MySubclassA)
implicit val MySubclassBFactory =
new Factory(() => new MySubclassB)
}
def myMethod[T <: MyClass](implicit factory: Factory[T]): Unit = {
val t = factory.make()
...
}
myMethod[MySubclassA] // works
myMethod[MyClass] // compilation error
myMethod[ASubclassForWhichFactoryIsNotDefined] // compilation error
You may use ClassTag
to achieve your goal:
def myMethod[T <: MyClass : ClassTag]: T =
implicitly[ClassTag[T]].runtimeClass.newInstance().asInstanceOf[T]
println(myMethod[MySubclassA]) // MySubclassA@66d2e7d9
println(myMethod[MySubclassB]) // MySubclassB@1efbd816