Méthode statique dans une classe générique?

En Java, j’aimerais avoir quelque chose comme:

class Clazz { static void doIt(T object) { // shake that booty } } 

Mais je reçois

  Impossible de faire une référence statique au type non statique T 

Je ne comprends pas les génériques au-delà des utilisations de base et je ne peux donc pas en tirer grand sens. Cela n’aide pas que je n’ai pas pu trouver beaucoup d’informations sur Internet à ce sujet.

Quelqu’un pourrait-il préciser si une telle utilisation est possible, de la même manière? Aussi, pourquoi ma tentative initiale a-t-elle échoué?

Vous ne pouvez pas utiliser les parameters de type génériques d’une classe dans les méthodes statiques ou les champs statiques. Les parameters de type de la classe sont uniquement dans la scope des méthodes d’instance et des champs d’instance. Pour les champs statiques et les méthodes statiques, ils sont partagés entre toutes les instances de la classe, même les instances de parameters de type différents, de sorte qu’ils ne peuvent évidemment pas dépendre d’un paramètre de type particulier.

Il ne semble pas que votre problème nécessite l’utilisation du paramètre type de la classe. Si vous décrivez plus en détail ce que vous essayez de faire, nous pouvons peut-être vous aider à trouver une meilleure façon de le faire.

Java ne sait pas ce que T est jusqu’à ce que vous instanciez un type.

Peut-être que vous pouvez exécuter des méthodes statiques en appelant Clazz.doit(something) mais cela semble impossible.

L’autre façon de gérer les choses consiste à placer le paramètre type dans la méthode elle-même:

 static  void doIt(U object) 

ce qui ne vous donne pas la bonne ressortingction sur U, mais c’est mieux que rien ….

J’ai rencontré ce même problème. J’ai trouvé ma réponse en téléchargeant le code source de Collections.sort dans le framework java. La réponse que j’ai utilisée était de mettre le générique dans la méthode, pas dans la définition de classe.

Donc cela a fonctionné:

 public class QuickSortArray { public static  void quickSort(T[] array, int bottom, int top){ //do it } } 

Bien sûr, après avoir lu les réponses ci-dessus, j’ai réalisé que ce serait une alternative acceptable sans utiliser de classe générique:

 public static void quickSort(Comparable[] array, int bottom, int top){ //do it } 

Il est possible de faire ce que vous voulez en utilisant la syntaxe des méthodes génériques lors de la déclaration de votre méthode doIt() (notez l’ajout de entre static et void dans la signature de méthode de doIt() ):

 class Clazz { static  void doIt(T object) { // shake that booty } } 

J’ai eu l’éditeur Eclipse pour accepter le code ci-dessus sans le fait de Cannot make a static reference to the non-static type T erreur de Cannot make a static reference to the non-static type T et ensuite étendu au programme de travail suivant (complet avec une référence culturelle un peu adaptée à l’âge):

 public class Clazz { static  void doIt(T object) { System.out.println("shake that booty '" + object.getClass().toSsortingng() + "' !!!"); } private static class KC { } private static class SunshineBand { } public static void main(Ssortingng args[]) { KC kc = new KC(); SunshineBand sunshineBand = new SunshineBand(); Clazz.doIt(kc); Clazz.doIt(sunshineBand); } } 

Qui imprime ces lignes sur la console quand je l’exécute:

secouez ce butin ‘classe com.eclipseoptions.datamanager.Clazz $ KC’ !!!
secouez ce butin ‘classe com.eclipseoptions.datamanager.Clazz $ SunshineBand’ !!!

Il est correctement mentionné dans l’erreur: vous ne pouvez pas faire une référence statique à un type non statique T. La raison est que le paramètre de type T peut être remplacé par n’importe quel argument de type Clazz ou Clazz etc. les champs / méthodes statiques sont partagés par tous les objects non statiques de la classe.

L’extrait suivant est tiré de la doc :

Le champ statique d’une classe est une variable de niveau classe partagée par tous les objects non statiques de la classe. Par conséquent, les champs statiques des parameters de type ne sont pas autorisés. Considérons la classe suivante:

 public class MobileDevice { private static T os; // ... } 

Si des champs statiques de parameters de type étaient autorisés, le code suivant serait confondu:

 MobileDevice phone = new MobileDevice<>(); MobileDevice pager = new MobileDevice<>(); MobileDevice pc = new MobileDevice<>(); 

Parce que le champ statique os est partagé par téléphone, pager et pc, quel est le type de système d’exploitation? Ce ne peut pas être Smartphone, Pager et TabletPC en même temps. Vous ne pouvez donc pas créer de champs statiques de parameters de type.

Comme Chris le souligne à juste titre dans sa réponse, vous devez utiliser le paramètre type avec la méthode et non avec la classe dans ce cas. Vous pouvez l’écrire comme:

 static  void doIt(E object) 

D’autres ont déjà répondu à votre question, mais je peux également recommander le livre O’Reilly Java Generics . C’est un sujet subtil et complexe par moments, et si souvent il semble y avoir des ressortingctions inutiles, mais le livre explique bien pourquoi les génériques Java sont comme ils sont.

Je pense que cette syntaxe n’a pas encore été mentionnée (dans le cas où vous voulez une méthode sans arguments):

 class Clazz { static  T doIt() { // shake that booty } } 

Et l’appel:

 Ssortingng str = Clazz.doIt(); 

J’espère que cela aidera quelqu’un.

Quelque chose comme ce qui suit vous rapprocherait

 class Clazz { public static  void doIt(U thing) { } } 

EDIT: Exemple mis à jour avec plus de détails

 public abstract class Thingo { public static  void doIt(U p_thingo) { p_thingo.thing(); } protected abstract void thing(); } class SubThingoOne extends Thingo { @Override protected void thing() { System.out.println("SubThingoOne"); } } class SubThingoTwo extends Thingo { @Override protected void thing() { System.out.println("SuThingoTwo"); } } public class ThingoTest { @Test public void test() { Thingo t1 = new SubThingoOne(); Thingo t2 = new SubThingoTwo(); Thingo.doIt(t1); Thingo.doIt(t2); // comstack error --> Thingo.doIt(new Object()); } } 

Lorsque vous spécifiez un type générique pour votre classe, la machine virtuelle Java ne le connaît que si elle possède une instance de votre classe et non une définition. Chaque définition n’a qu’un type paramétré.

Les génériques fonctionnent comme des modèles en C ++, vous devez donc d’abord instancier votre classe, puis utiliser la fonction avec le type spécifié.

En termes simples, cela se produit à cause de la propriété “Erasure” des génériques. Cela signifie que bien que nous définissions ArrayList et ArrayList , au moment de la compilation, il rest deux types de béton différents mais à Lors de l’exécution, la machine virtuelle Java efface les types génériques et crée une seule classe ArrayList au lieu de deux classes. Donc, quand on définit une méthode de type statique ou quelque chose pour un générique, elle est partagée par toutes les instances de ce générique, dans mon exemple elle est partagée par ArrayList et ArrayList . C’est pourquoi vous obtenez l’erreur.A Le paramètre de type générique d’une classe n’est pas autorisé dans un contexte statique!

@BD at Rivenhill: Comme cette vieille question a suscité un regain d’attention l’année dernière, continuons un peu, juste pour des raisons de discussion. Le corps de votre méthode doIt ne fait rien du tout. C’est ici:

 public class Clazz { static  void doIt(T object) { System.out.println("shake that booty '" + object.getClass().toSsortingng() + "' !!!"); } // ... } 

Ainsi, vous pouvez supprimer entièrement toutes les variables de type et simplement coder

 public class Clazz { static void doIt(Object object) { System.out.println("shake that booty '" + object.getClass().toSsortingng() + "' !!!"); } // ... } 

D’accord. Mais revenons au problème initial. La première variable de type de la déclaration de classe est redondante. Seul le second sur la méthode est nécessaire. C’est reparti, mais ce n’est pas la réponse finale, pourtant:

 public class Clazz { static  void doIt(T object) { System.out.println("shake that booty "+ object.say()); } public static void main(Ssortingng args[]) { Clazz.doIt(new KC()); Clazz.doIt(new SunshineBand()); } } // Output: // KC // Sunshine interface Saying { public Ssortingng say(); } class KC implements Saying { public Ssortingng say() { return "KC"; } } class SunshineBand implements Saying { public Ssortingng say() { return "Sunshine"; } } 

Cependant, rien n’est trop compliqué, car la version suivante fonctionne de la même manière. Tout ce dont il a besoin est le type d’interface sur le paramètre de méthode. Aucune variable de type en vue nulle part. Était-ce vraiment le problème original?

 public class Clazz { static void doIt(Saying object) { System.out.println("shake that booty "+ object.say()); } public static void main(Ssortingng args[]) { Clazz.doIt(new KC()); Clazz.doIt(new SunshineBand()); } } interface Saying { public Ssortingng say(); } class KC implements Saying { public Ssortingng say() { return "KC"; } } class SunshineBand implements Saying { public Ssortingng say() { return "Sunshine"; } } 

Puisque les variables statiques sont partagées par toutes les instances de la classe. Par exemple si vous avez le code suivant

 class Class { static void doIt(T object) { // using T here } } 

T est disponible uniquement après la création d’une instance. Mais les méthodes statiques peuvent être utilisées avant même que les instances ne soient disponibles. Ainsi, les parameters de type générique ne peuvent pas être référencés dans les méthodes statiques et les variables