Dans la classe générique Java, ajoutez des contraintes génériques supplémentaires au niveau du constructeur?
, j'ai une interface appelée Bar
et une classe générique Foo
paramétrée sur un type est un Bar
:
class Foo<B extends Bar> { }
Ma classe a un constructeur à usage général qui prend un Class
et un Stream
:
class Foo<B extends Bar> {
B[] bs;
Foo(Class<B> clazz, Stream<B> stream) { // General ctor
bs = someFunctionOf(clazz, stream);
}
}
J'essaie d'ajouter un constructeur spécialisé qui nécessite que son paramètre de méthode réel both soit un Bar
et une classe enum
telle que je puisse appeler mon constructeur à usage général à partir du constructeur spécial:
class Foo<B extends Bar> {
B[] bs;
Foo(Class<B> clazz, Stream<B> stream) { // General ctor
bs = someFunctionOf(clazz, stream);
}
// FIX THIS ----+
// |
// ˅
Foo(Class<Something> clazz) { // Special ctor
// Can we make this work so Something is a Bar and an enum
// and we can call the other constructor like this?
this(clazz, Arrays.stream(clazz.getEnumConstants());
}
}
3 answers
De manière générale, vous pouvez écrire des constructeurs génériques. Nous avons récemment eu une question à leur sujet, et comment ils pourraient être utiles. De cette façon, vous pouvez fournir un constructeur qui prend comme argument une classe représentant une classe qui étend à la fois une autre classe spécifique et implémente l'interface Bar
:
class Foo<B extends Bar> {
B[] bs;
Foo(Class<B> clazz, Stream<B> stream) { // General ctor
bs = someFunctionOf(clazz, stream);
}
private B[] someFunctionOf(Class<B> clazz, Stream<B> stream) {
return null;
}
<T extends SomeClass & Bar> Foo(Class<T> clazz) {
// ...
}
}
Mais cela ne vous amène pas tout à fait où vous voulez être, car les limites de l'argument de type du constructeur T
doivent être des types explicites. Les variables de Type tel que le paramètre de type de la classe B
ne sert pas, et sans moyen de connecter T
à B
, le constructeur générique spécial ne peut pas invoquer le constructeur général.
Mais vous pouvez le faire avec une méthode factory au lieu d'un constructeur spécial:
class Foo<B extends Bar> {
B[] bs;
Foo(Class<B> clazz, Stream<B> stream) { // General ctor
bs = someFunctionOf(clazz, stream);
}
private B[] someFunctionOf(Class<B> clazz, Stream<B> stream) {
return null;
}
static <T extends Enum<T> & Bar> Foo<T> createEnumFoo(Class<T> clazz) {
return new Foo<>(clazz, Arrays.stream(clazz.getEnumConstants()));
}
}
Je ne pense pas que vous puissiez le faire avec le constructeur. Soit créer une sous-classe:
class EnumFoo<B extends Enum<B>&Bar> extends Foo<B> {
public EnumFoo(Class<B> clazz) {
super(clazz, Arrays.stream(clazz.getEnumConstants()));
}
}
Ou méthode d'usine:
public static <T extends Enum<T>&Bar> Foo<T> of(Class<T> clazz) {
return new Foo<>(clazz, Arrays.stream(clazz.getEnumConstants()));
}
Ceci est possible en utilisant l'opérateur&: <Something extends Bar & Enum<?>>