Objet d'instanciation du paramètre de type


88

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?

Réponses:


85

Après l'effacement de type, tout ce que l'on sait, Tc'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 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 utiliser 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();
  }

}

Dans quel paquet Supplierse trouve-t-il? `MyClass (Class <? Extend T> impl)` doit déclarer `throws NoSuchMethodException` pour être compilé. Votre réponse n'est malheureusement pas adaptée aux débutants en Java.
purucat

@ user927387java.util.function.Supplier
erickson

Le fournisseur <T> nécessite Java 8, JFTR pour tout ce qui en vaut la peine.
Fran Marzoa

14

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

Dans Effective Java, Joshua Bloch passe en revue 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 concrets peuvent implémenter cette interface, et les classes extérieures peuvent utiliser le constructeur concret pour configurer le constructeur selon les besoins. Le générateur peut être transmis à MyClass en tant que fichier Builder<T>.

En utilisant ce modèle, vous pouvez obtenir de nouvelles instances de T, même si elle Ta 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 transmettre à MyClass, alors Builder et Abstract Factory sont sortis.


12

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 lorsqu'elle est construite au lieu de la passer dans votre méthode à chaque fois qu'elle est appelée.

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

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

1
Bonne approche non réfléchie; la réflexion n'est pas toujours une option. myMethod devrait pouvoir accepter un MyFactory <? étend T>, non?
erickson

1
Bon appel - vous voudrez mettre un caractère générique borné sur la fabrique pour permettre aux objets de type T et aux sous-classes de T d'être créés dans myMethod ().
Dan Hodge


-3

Classe classOfT

        try {
            t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
        } catch (Exception e) {
            e.printStackTrace();
        }

2
Où cette classe classOfT est-elle déclarée?
Fran Marzoa
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.