Eu tenho uma classe de modelo como segue:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Como faço para criar uma nova instância de T em minha classe?
Eu tenho uma classe de modelo como segue:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Como faço para criar uma nova instância de T em minha classe?
Respostas:
Após a eliminação do tipo, tudo o que se sabe T
é que se trata de uma subclasse de Object
. Você precisa especificar alguma fábrica para criar instâncias T
.
Uma abordagem poderia usar 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();
}
}
O uso pode ser assim:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Como alternativa, você pode fornecer um Class<T>
objeto e, em seguida, usar reflexão.
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
Outra abordagem não reflexiva é usar um padrão híbrido Builder / Abstract Factory.
Em Effective Java, Joshua Bloch examina o padrão Builder em detalhes e defende uma interface Builder genérica:
public interface Builder<T> {
public T build();
}
Construtores concretos podem implementar esta interface e classes externas podem usar o construtor concreto para configurar o Construtor conforme necessário. O construtor pode ser passado para MyClass como um Builder<T>
.
Usando esse padrão, você pode obter novas instâncias de T
, mesmo que T
tenha parâmetros de construtor ou exija configuração adicional. Obviamente, você precisará de alguma forma de passar o Builder para MyClass. Se você não pode passar nada para MyClass, então Builder e Abstract Factory estão fora.
Isso pode ser mais pesado do que o que você está procurando, mas também funcionará. Observe que, se você adotar essa abordagem, faria mais sentido injetar a fábrica em MyClass quando ela for construída, em vez de passá-la para seu método cada vez que for chamada.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Se você deseja criar uma subclasse, também pode evitar o apagamento, consulte 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
está localizado? `MyClass (Class <? Extends T> impl)` deve declarar `throws NoSuchMethodException` para ser compilado. Sua resposta infelizmente não é amigável para iniciantes em Java.