Question À quoi servent les constructeurs génériques en Java?


Comme tout le monde le sait, vous pouvez avoir une classe générique en Java en utilisant des arguments de type:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}

Mais vous pouvez aussi avoir générique constructeurs, ce qui signifie des constructeurs qui reçoivent explicitement leurs propres arguments de type générique, par exemple:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

J'ai du mal à comprendre le cas d'utilisation. Qu'est-ce que cette fonctionnalité me permet de faire?


34
2017-12-14 05:33


origine


Réponses:


Qu'est-ce que cette fonctionnalité me permet de faire?

Il y a au moins Trois deux choses vous permettent de faire ce que vous ne pourriez pas faire autrement:

  1. exprimer les relations entre les types d'arguments, par exemple:

    class Bar {
        <T> Bar(T object, Class<T> type) {
            // 'type' must represent a class to which 'object' is assignable,
            // albeit not necessarily 'object''s exact class.
            // ...
        }
    }
    
  2. <retiré>

  3. Comme @Lino l’a observé en premier, il vous permet d’exprimer que les arguments doivent être compatibles avec une combinaison de deux types différents ou non (ce qui peut avoir un sens lorsque tous les types d’interface, sauf un, sont au maximum). Voir la réponse de Lino pour un exemple.


15
2017-12-14 15:50



Le cas d'utilisation auquel je pense pourrait être que certains veulent un objet qui hérite de 2 types. Par exemple. implémente 2 interfaces:

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}

Bien que je ne l'ai jamais utilisé en production.


22
2017-12-14 11:52



Il est clair dans l'exemple que vous avez fourni que U ne joue aucun rôle dans le constructeur de la classe, car il devient effectivement un Object lors de l'exécution:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

Mais disons que je voulais que mon constructeur n'accepte que les types qui étendent une autre classe ou une autre interface, comme ci-dessous:

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}

Notez que la classe a déjà un type générique différent en cours d'utilisation; Cela vous permet d'utiliser un type générique distinct et indépendant de la définition de classe.

Certes, je n'ai jamais utilisé quelque chose comme ça et je ne l'ai jamais vu utiliser, mais c'est possible!


19
2017-12-14 05:43



En fait, ce constructeur

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

est juste comme un méthode générique. Cela aurait beaucoup plus de sens si vous aviez plusieurs arguments de constructeur comme celui-ci:

class Bar {
    <U> Bar(U you, U me) {
        // Why!?
    }
} 

Ensuite, vous pouvez appliquer la contrainte, à savoir qu'ils ont le même temps avec le compilateur. Sans faire de U un générique pour toute la classe.


10
2017-12-14 08:03



Parce que ce type générique non lié efface Object, ce serait comme passer Object dans votre constructeur:

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}

... mais comme passer un blanc Object, sauf si vous faites quelque chose intelligent, cela a peu de valeur pratique.

Vous voyez des avantages et gagnez si vous passez lié génériques au lieu de cela, ce qui signifie que vous pouvez réellement avoir des garanties autour du type qui vous intéresse.

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}

En réalité, il s’agit plus de flexibilité que d’être révolutionnaire. Si vous souhaitez avoir la flexibilité nécessaire pour passer dans une catégorie spécifique de types, vous avez le pouvoir de le faire ici. Si vous ne pas, alors il n'y a rien de mal avec les classes standard. C'est simplement ici pour votre commodité, et puisque l'effacement de type est toujours une chose, un générique non lié est le même (et a le même utilitaire) que le passage Object.


8
2017-12-14 05:42