web-dev-qa-db-fra.com

Instanciation d'un objet de type paramètre

J'ai une classe de modèle comme suit:

class MyClass<T>
{
    T field;
    public void myMethod()
    {
       field = new T(); // gives compiler error
    }
}

Comment créer une nouvelle instance de T dans ma classe?

77
Mercurious

Après l'effacement de type, tout ce que l'on sait sur T, c'est qu'il s'agit d'une sous-classe de Object. Vous devez spécifier une fabrique pour créer des instances de T.

Une approche pourrait utiliser 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();
  }

}

L'utilisation pourrait ressembler à ceci:

MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);

Vous pouvez également fournir un Class<T> objet, puis utilisez la réflexion.

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();
  }

}
75
erickson

Une autre approche non réfléchissante consiste à utiliser un modèle hybride Builder/Abstract Factory.

Dans Effective Java, Joshua Bloch revient sur le modèle Builder en détail et préconise une interface Builder générique:

public interface Builder<T> {
  public T build();
}

Les constructeurs de béton peuvent implémenter cette interface et les classes externes peuvent utiliser le générateur de béton pour configurer le générateur selon les besoins. Le générateur peut être transmis à MyClass en tant que Builder<T>.

En utilisant ce modèle, vous pouvez obtenir de nouvelles instances de T, même si T a des paramètres de constructeur ou nécessite une configuration supplémentaire. Bien sûr, vous aurez besoin d'un moyen de passer le générateur dans MyClass. Si vous ne pouvez rien passer dans MyClass, alors Builder et Abstract Factory sont sortis.

13
InverseFalcon

Cela peut être plus lourd que ce que vous recherchez, mais cela fonctionnera également. Notez que si vous adoptez cette approche, il serait plus logique d'injecter la fabrique dans MyClass lors de sa construction au lieu de la passer dans votre méthode à chaque appel.

interface MyFactory<T> 
{
    T newObject();
}

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}
11
Dan Hodge

Si vous êtes prêt à sous-classer, vous pouvez également éviter l'effacement, consultez http://www.artima.com/weblogs/viewpost.jsp?thread=20886

1
krosenvold