Ho una classe modello come segue:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Come creo una nuova istanza di T nella mia classe?
Risposte:
Dopo la cancellazione del tipo, tutto ciò che si sa T
è che si tratta di una sottoclasse di Object
. È necessario specificare una fabbrica di cui creare istanze T
.
Un approccio potrebbe utilizzare Supplier<T>
:
class MyClass<T> {
private final Supplier<? extends T> ctor;
private T field;
MyClass(Supplier<? extends T> ctor) {
this.ctor = Objects.requireNonNull(ctor);
}
public void myMethod() {
field = ctor.get();
}
}
L'utilizzo potrebbe essere simile a questo:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
In alternativa, puoi fornire un Class<T>
oggetto e quindi utilizzare la riflessione.
class MyClass<T> {
private final Constructor<? extends T> ctor;
private T field;
MyClass(Class<? extends T> impl) throws NoSuchMethodException {
this.ctor = impl.getConstructor();
}
public void myMethod() throws Exception {
field = ctor.newInstance();
}
}
java.util.function.Supplier
Un altro approccio non riflettente consiste nell'usare un modello ibrido Builder / Abstract Factory.
In Effective Java, Joshua Bloch esamina in dettaglio il pattern Builder e sostiene un'interfaccia Builder generica:
public interface Builder<T> {
public T build();
}
I costruttori di calcestruzzo possono implementare questa interfaccia e le classi esterne possono utilizzare il generatore di calcestruzzo per configurare il generatore come richiesto. Il builder può essere passato a MyClass come file Builder<T>
.
Utilizzando questo modello, è possibile ottenere nuove istanze di T
, anche se T
dispone di parametri del costruttore o richiede una configurazione aggiuntiva. Ovviamente, avrai bisogno di un modo per passare il Builder in MyClass. Se non puoi passare nulla a MyClass, Builder e Abstract Factory sono fuori.
Questo potrebbe essere più pesante di quello che stai cercando, ma funzionerà anche. Nota che se adotti questo approccio, avrebbe più senso iniettare la factory in MyClass quando viene costruita invece di passarla nel tuo metodo ogni volta che viene chiamata.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Se sei disposto a creare una sottoclasse, puoi anche evitare la cancellazione, controlla http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Class classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
si trova? `MyClass (Class <? Extends T> impl)` deve dichiarare `throws NoSuchMethodException` per essere compilato. La tua risposta purtroppo non è amichevole per i principianti di Java.