2016-10-19 4 views
1

Ich habe eine Klasse mit einem generischen Typparameter und möchte eine Instanz dieses Typs mit Reflection erstellen. Außerdem hat der Typ einen privaten Konstruktor. Hier ist ein Codebeispiel des Problems:Scala: Instanz aus generischem Typ mit privatem Konstruktor erstellen

class X private (x: Int) { 
} 
class Y private (y: Int) { 
} 
abstract class Foo[T](z : Int) { 
    var bar : T = createInstance[T](z) 
    def createInstance[T](z: Int) : M = { 
    ??? 
    } 
} 

Dies würde mir erlauben, Foo und Bar Zugang zu instanziieren:

class xFoo extends Foo[X]{ 
} 

class yFoo extends Foo[Y]{ 
} 

var xfoo = new xFoo(5) 
println(xfoo.bar.x) 

var yfoo = new yFoo(6) 
println(yfoo.bar.y) 

Dies sollte auszudrucken '5' und '6'.

Ich habe versucht, implizit auf folgende Weise.

def createInstance[T](z: Int)(implicit tag: TypeTag[T]) : T = { 
    val clazz = tag.tpe.getClass 
    val ctor = class.getDeclaredConstructor(classOf[Int]) 
    ctor.setAccessible(true) 
    return ctor.newInstance(z).asInstanceOf[T] 
} 

aber dann bekomme ich den Fehler:

No TypeTag available for T 

in Linie

var bar : T = createInstance[T](z) 

Irgendwelche Vorschläge? Danke für Ihre Hilfe!

+0

Ich denke, dass Sie 'scala.reflect.ClassTag' anstelle von' TypeTag' verwenden sollten. –

+0

Willst du wirklich, dass 'createInstance' einen eigenen' T' Typparameter hat, der sich von 'Foo's unterscheidet? –

Antwort

1

Unter der Annahme, dass die Super-Klasse eine Methode/Wert aussetzt Sie wie gesuchte:

class X private(val x: Int) {} 

Sie können es erweitern, wie so:

import scala.reflect._ 

class Foo[T](z : Int)(implicit ct: ClassTag[T]) { 
    var bar : T = createInstance[T](z) 
    def createInstance[T](z: Int) : T = { 
    val ctor = ct.runtimeClass.getDeclaredConstructor(classOf[Int]) 
    ctor.setAccessible(true) 
    ctor.newInstance(Int.box(4)).asInstanceOf[T] 
    } 
} 

So können Sie rufen Sie an:

class XFoo(n: Int) extends Foo[X](n) 
println((new XFoo(5)).bar.x) 
+0

Danke, aber in der Zeile –

+0

Danke, aber in der Zeile val ctor = classTag [X] .runtimeClass.getDeclaredConstructor (classOf [Int]) Sie verwenden classTag [X]. Sollte das nicht classTag [T] sein? –

+0

Sorry, ich denke meine Frage war nicht präzise genug. Die abstrakte Klasse Foo sollte als Basisklasse für mehrere Klassen dienen, die sich in ihrem Typ T unterscheiden: xFoo erweitert Foo [X] yFoo erweitert Foo [Y] –

Verwandte Themen