Comment rendre statique une méthode Java Generic?

173

Ce qui suit est un extrait de code sur la façon de créer une classe générique java pour ajouter un seul élément à un tableau. Comment puis-je faire de appendToArray une méthode statique. L'ajout de statique à la signature de méthode entraîne des erreurs de compilation.

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}
Chris Johnson
la source
Quelles erreurs de compilation obtenez-vous? Aussi, pourquoi ne pas simplement utiliser l'un des conteneurs de bibliothèque standard?
Karl Knechtel
1
Erreur de compilation: j'ajoutais en fait le modificateur statique incorrect. Utilisation des collections: Oui, l'utilisation d'une collection serait idéale, mais la question ne concerne pas les collections par rapport aux tableaux, mon cas d'utilisation nécessite un tableau.
Chris Johnson
Notez que vous devrez utiliser la réflexion (EVIL) pour empêcher le code client de lancer une exception dans certaines circonstances, mais pas dans toutes (bien). Il est préférable d'éviter les tableaux de référence.
Tom Hawtin - tackline

Réponses:

283

la seule chose que vous pouvez faire est de changer votre signature en

public static <E> E[] appendToArray(E[] array, E item)

Détails importants:

Les expressions génériques précédant la valeur de retour introduisent (déclarent) toujours une nouvelle variable de type générique.

De plus, les variables de type entre les types ( ArrayUtils) et les méthodes statiques ( appendToArray) n'interfèrent jamais les unes avec les autres.

Alors, qu'est - ce que cela veut dire: Dans ma réponse <E>cacherait la Ede ArrayUtils<E>si la méthode ne serait pas static. AND <E>n'a rien à voir avec le Efrom ArrayUtils<E>.

Pour mieux refléter ce fait, une réponse plus correcte serait:

public static <I> I[] appendToArray(I[] array, I item)
Scheffield
la source
30
Veuillez également noter qu'il n'y a absolument aucune relation entre la variable de type au niveau de la classe Eet la variable de type de méthode statique E. Je considère qu'il est préférable d'utiliser un nom de variable différent lors de la déclaration de méthodes génériques, statiques ou non, à l'intérieur de classes génériques.
Judge Mental
mais dans ce cas, je peux passer un objet de différents types dans les paramètres. Comme je peux passer le tableau Integer [] comme premier paramètre et élément Double.
pinkpanther
pinkpanther: C'est vrai, mais cela ne fait aucun mal, car la méthode statique n'opère que sur un objet tableau qui lui est passé via un paramètre, donc ses éléments sont sûrs d'avoir le type correct.
Dabbler
80
public static <E> E[] appendToArray(E[] array, E item) { ...

Notez le <E>.

Les méthodes génériques statiques ont besoin de leur propre déclaration générique ( public static <E>) distincte de la déclaration générique de la classe ( public class ArrayUtils<E>).

Si le compilateur se plaint d'une ambiguïté de type en invoquant une méthode générique statique (encore une fois peu probable dans votre cas, mais, en général, juste au cas où), voici comment invoquer explicitement une méthode générique statique en utilisant un type spécifique ( _class_.<_generictypeparams_>_methodname_):

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

Cela ne se produirait que si le compilateur ne peut pas déterminer le type générique parce que, par exemple, le type générique n'est pas lié aux arguments de la méthode.

Bert F
la source
10

Vous devez déplacer le paramètre de type au niveau de la méthode pour indiquer que vous avez une méthode générique plutôt qu'une classe générique:

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}
axtavt
la source
1
Cela ne fonctionnera pas car vous n'avez pas défini le type générique E. Dans ce cas, vous devez toujours avoir le type générique <E> dans la définition de classe.
George Xavier
0

Je vais l'expliquer d'une manière simple.

Les génériques définis au niveau de la classe sont complètement séparés des génériques définis au niveau de la méthode (statique).

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

Lorsque vous voyez le code ci-dessus n'importe où, veuillez noter que le T défini au niveau de la classe n'a rien à voir avec le T défini dans la méthode statique. Le code suivant est également entièrement valide et équivalent au code ci-dessus.

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

Pourquoi la méthode statique doit-elle avoir ses propres génériques séparés de ceux de la classe?

En effet, la méthode statique peut être appelée sans même instancier la classe. Donc, si la classe n'est pas encore instanciée, nous ne savons pas encore ce qu'est T. C'est la raison pour laquelle les méthodes statiques doivent avoir leurs propres génériques.

Ainsi, chaque fois que vous appelez la méthode statique,

Greet.sayHello("Bob");
Greet.sayHello(123);

JVM l'interprète comme suit.

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

Les deux donnant les mêmes sorties.

Hello Bob
Hello 123
Vishnu Vivek
la source