Tengo una clase de plantilla de la siguiente manera:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
¿Cómo creo una nueva instancia de T en mi clase?
Tengo una clase de plantilla de la siguiente manera:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
¿Cómo creo una nueva instancia de T en mi clase?
Respuestas:
Después del borrado de tipo, todo lo que se sabe T
es que es una subclase de Object
. Necesita especificar alguna fábrica para crear instancias T
.
Un enfoque podría usar un 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();
}
}
El uso podría verse así:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Alternativamente, puede proporcionar un Class<T>
objeto y luego usar la reflexión.
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
Otro enfoque no reflexivo es utilizar un patrón híbrido Builder / Abstract Factory.
En Effective Java, Joshua Bloch repasa el patrón Builder en detalle y aboga por una interfaz Builder genérica:
public interface Builder<T> {
public T build();
}
Los constructores de hormigón pueden implementar esta interfaz, y las clases externas pueden utilizar el constructor de hormigón para configurar el Constructor según sea necesario. El constructor se puede pasar a MyClass como Builder<T>
.
Con este patrón, puede obtener nuevas instancias de T
, incluso si T
tiene parámetros de constructor o requiere configuración adicional. Por supuesto, necesitará alguna forma de pasar el Constructor a MyClass. Si no puede pasar nada a MyClass, entonces Builder y Abstract Factory están fuera.
Esto puede ser más pesado de lo que está buscando, pero también funcionará. Tenga en cuenta que si adopta este enfoque, tendría más sentido inyectar la fábrica en MyClass cuando se construye en lugar de pasarla a su método cada vez que se llama.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Si está dispuesto a realizar una subclase, también puede evitar el borrado, consulte http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Clase classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
se encuentra? `MyClass (Class <? Extiende T> impl)` debe declarar `throws NoSuchMethodException` para ser compilado. Desafortunadamente, su respuesta no es amigable para los principiantes de Java.