Partage
  • Partager sur Facebook
  • Partager sur Twitter

Méthodes d'un générique

Sujet résolu
    24 mai 2015 à 15:59:03

    Bonjour !

    J'essaye de créer une classe Launcher<T> qui permettrait d’exécuter un programme java passer en tant que paramètre générique T.

    En gros, je voudrais que mon Launcher puisse exécuter le main d'une classe qu'on lui passerait en tant que générique.

    Pour ça j'ai essayé de faire comme suivant : 

    public class ClasseUtiliserControleur<T> {
    
    	private T valeur;
    	
    	public ClasseUtiliserControleur() {
    	    this.valeur = null;
    	}
    
    	public ClasseUtiliserControleur(T val){
    		this.valeur = val;
    	}
    	
    	public void lancerControleur(){
    		String[] args = new String[0];
    		valeur.main(args);
    	}
    }
    

    Le problème est que vu que la variable T passé en argument n'a pas forcément de main, Eclipse me dit "The method main(String[]) is undefined for the type T"

    Je ne sais pas vraiment comment faire du coup... Je voudrais que mon programme ait un effet similaire à la commande "java monProgramme" mais pas qu'il se contente d'éxécuter cette commande, je voudrais vraiment qu'il lance la méthode main au cas ou je veuille utiliser une autre méthode de ma classe T comme par exemple valeur.getUneVariable();

    Merci d'avance de vos réponses :)

    -
    Edité par Maxime O. 24 mai 2015 à 16:00:02

    • Partager sur Facebook
    • Partager sur Twitter
      25 mai 2015 à 19:44:49

      Bonjour.

      Tu peux "typer" le paramètre T pour accéder à ses fonctionnalités.

      interface Toto {
          void main(String[] args);
      }
      
      class ClasseUtiliserControleur<T extends Toto> {
          private T valeur;
          
          public ClasseUtiliserControleur() {
              this.valeur = null;
          }
      
          public ClasseUtiliserControleur(T val){
              this.valeur = val;
          }
          
          public void lancerControleur(){
              String[] args = new String[0];
              valeur.main(args);
          }
      }

      Lors de l'utilisation, ta classe devras bien évidemment être de ce type :

      class Test1 implements Toto {
          @Override
          public void main(String[] args) {
              // ...
          }
      }
      
      class Test2 implements Toto {
          @Override
          public void main(String[] args) {
              // ...
          }
      }
      
      // utilisation
      ClasseUtiliserControleur<Test1> runner1 = new ClasseUtiliserControleur<>(new Test1());
      ClasseUtiliserControleur<Test2> runner2 = new ClasseUtiliserControleur<>(new Test2());
      ClasseUtiliserControleur<? extends Toto> runnerX = new ClasseUtiliserControleur<>(new Test2());
      • Partager sur Facebook
      • Partager sur Twitter
      Angular 2 est l'avenir, jQuery c'est de la merde !!! - Java 8 c'est l'an 2016+ (programmez en 1 ligne)
        25 mai 2015 à 19:54:44

        Merci ça marche ! Problème résolu :)

        • Partager sur Facebook
        • Partager sur Twitter
          26 mai 2015 à 10:54:00

          Mince excuse moi j'ai crié victoire trop vite.

          J'ai essayé de faire ça :

          - Classe Launcher1 :

          interface Launchable {
              void main(String[] args);
          }
          
          public class Launcher1<T extends Launchable> {
          
          	private T valeur;
          	
          	public Launcher1() {
          	    this.valeur = null;
          	}
          
          	public Launcher1(T val){
          		this.valeur = val;
          	}
          	
          	public void lancerControleur(){
          		String[] args = new String[0];
          		valeur.main(args);
          	}
          }
          

          - Classe Test1ALancer :

          public class Test1ALancer implements Launchable{
          	public void main(String[] args){
          		System.out.println("Worked fine !");
          	}
          }
          

          - Classe LaunchTest : 

          public class LaunchTest {
          	private static Launcher1<Test1ALancer> l;
          	
          	public static void main(String[] args){
          		System.out.println("Lancement en cours...");
          		l = new Launcher1<Test1ALancer>();
          		l.lancerControleur();
          	}
          }
          

          Aucune erreur de compilation, je me disais que ça marchait.

          Finalement j'ai essayé de le lancer, en gros la dernière classe "LaunchTest" essaye de lancer la classe "Test1ALancer" via la classe "Launcher1"

          Et voilà ce que m'affiche la console : 

          Lancement en cours...
          Exception in thread "main" java.lang.NullPointerException
          	at Launcher1.lancerControleur(Launcher1.java:19)
          	at LaunchTest.main(LaunchTest.java:7)
          

          Le problème vient de la ligne 19 de la classe "Launcher1"

          valeur.main(args);

          Je ne comprend pas d'où vient le problème, tu as une idée ?





          • Partager sur Facebook
          • Partager sur Twitter
            26 mai 2015 à 11:06:01

            NullPointerException : tu appelles une méthode sur un objet null.
            Ensuite à toi de savoir quelle ligne plante (voir stack-trace), quelle variable est null, et pourquoi.

            Je ne te donnerai pas la réponse car il s'agit d'un problème bateau que tu dois apprendre à résoudre seul car tu le rencontreras tout le temps.
            Le seul indice que je peux te donner est : "Quelle est l'utilité du constructeur par défaut public Launcher1() { this.valeur = null; } ?"

            • Partager sur Facebook
            • Partager sur Twitter
            Angular 2 est l'avenir, jQuery c'est de la merde !!! - Java 8 c'est l'an 2016+ (programmez en 1 ligne)
              26 mai 2015 à 12:07:31

              Mais oui c'est évident en plus ! :-°

              C'est bon ça marche j'ai corrigé la classe LaunchTest : 

              public class LaunchTest {
              	private static Launcher1<Test1ALancer> l;
              	
              	public static void main(String[] args){
              		System.out.println("Lancement en cours...");
              		l = new Launcher1<>(new Test1ALancer());
              		l.lancerControleur();
              	}
              }
              

              Du coup là ça marche... Je me sens un peu bête :p

              Par contre le principe que je voulais c'est que le launcher puisse lancer n'importe quelle classe sans la (trop) la modifier, par exemple simplement rajouter "extends Launchable"

              Le problème c'est que je dois modifier le "public static void main(String[] args" que l'on trouve dans n'importe quel programme éxécutable par un "public void main(String[] args" qui fait que le programme n'est plus indépendant, on ne peut pas l'éxecuter tel quel.

              Sauf que dans l'interface Launchable si je met :

              interface Launchable {
                  public static void main(String[] args);
              }

              dans la méthode "lancerControleur" j'ai une erreur à la ligne : "valeur.main(args);" :

              	public void lancerControleur(){
              		String[] args = new String[0];
              		valeur.main(args);
              	}


              J'ai l'erreur suivante : The method main(String[]) is undefined for the type T

              J'ai donc aucun moyen de pouvoir lancer le main sans modifier la ligne ?

              • Partager sur Facebook
              • Partager sur Twitter
                26 mai 2015 à 12:26:10

                Ce que tu veux c'est utiliser le polymorphisme, qui s'applique sur des objets.
                Le problème ici c'est que la méthodes main est statique, donc tu ne peux pas utiliser cette fonctionnalité.
                De plus, une méthode statique dans une interface le permet pas d'utiliser le polymorphisme.

                Une solution simple serait de déporter le code de ton main vers une méthode d'objet, ou plus simplement vers la méthode que tu souhaites exécuter.

                interface Launchable {
                    void launch(String[] args);
                }
                
                class Test1ALancer implements Launchable {
                	public static void main(String[] args) {
                		new Test1ALancer().launch(args); // cela te permet de garder la méthode main
                	}
                	
                	// cela te permet d'utiliser le polymorphisme car tu es au niveau "objet"
                	@Overrides
                	public void launch(String[] args) {
                		// ton traitement qui était initialement dans le main
                	}
                }
                
                public class Launcher1<T extends Launchable> {
                    private T valeur;
                
                    public Launcher1(T val){
                        this.valeur = val;
                    }
                
                    public void lancerControleur() {
                        String[] args = new String[0];
                        valeur.launch(args);
                    }
                }
                
                // Utilisation
                public class LaunchTest {
                	public static void main(String[] args){
                		System.out.println("Lancement en cours...");
                		
                		Launcher1<Test1ALancer> l = new Launcher1<>(new Test1ALancer());
                		l.lancerControleur();
                	}
                }

                L'autre solution un peu plus complexe à comprendre serait de passer en paramètre une implémentation de Launchable qui se chargerait d'appeler le main correspondant :
                Cette solution est plus propre car tu n'as pas besoin de modifier le code initial. 

                interface Launchable {
                    void launch(String[] args);
                }
                
                class Test1ALancer {
                    public static void main(String[] args) {
                        // ton traitement qui est initialement dans le main
                    }
                }
                
                class Launcher1<T extends Launchable> {
                    private T valeur;
                
                    public Launcher1(T val) {
                        this.valeur = val;
                    }
                
                    public void lancerControleur() {
                        String[] args = new String[0];
                        valeur.launch(args);
                    }
                }
                
                // Utilisation
                class LaunchTest {
                    public static void main(String[] args) {
                        System.out.println("Lancement en cours...");
                
                        // Lambda :
                        Launcher1<Launchable> l1 = new Launcher1<>(x -> Test1ALancer.main(x));
                        l1.lancerControleur();
                        // Classe anonyme :
                        Launcher1<Launchable> l2 = new Launcher1<>(new Launchable() {
                            @Override
                            public void launch(String[] args) {
                                Test1ALancer.main(args);
                            }
                        });
                        l2.lancerControleur();
                    }
                }

                -
                Edité par Pinguet62 26 mai 2015 à 12:51:02

                • Partager sur Facebook
                • Partager sur Twitter
                Angular 2 est l'avenir, jQuery c'est de la merde !!! - Java 8 c'est l'an 2016+ (programmez en 1 ligne)
                  26 mai 2015 à 12:48:56

                  J'en ai parlé à un ami et il m'a donné une idée :

                  rajouter dans la classe à éxecuter une méthode "lancer()" qui contiendrait ce code :

                  public void lancer() {
                  	String[] args = new String[0];
                  	main(args);
                  }


                  De cette façon, voici à quoi ressemble la classe Launcher1 :

                  interface Launchable {
                      void lancer();
                  }
                  
                  public class Launcher1<T extends Launchable> {
                  
                  	private T valeur;
                  	
                  	public Launcher1() {
                  	    this.valeur = null;
                  	}
                  
                  	public Launcher1(T val){
                  		this.valeur = val;
                  	}
                  	
                  	public void lancerControleur(){
                  		valeur.lancer();
                  	}
                  }
                  

                  LaunchTest : 

                  public class LaunchTest {
                  	private static Launcher1<Test1ALancer> l;
                  	
                  	public static void main(String[] args){
                  		System.out.println("Lancement en cours...");
                  		l = new Launcher1<>(new Test1ALancer());
                  		l.lancerControleur();
                  	}
                  }
                  

                  Et la classe Test1ALancer, qui represente la classe que le launcher doit éxecuter :

                  public class Test1ALancer implements Launchable{
                  	
                  	public static void main(String[] args){
                  		System.out.println("Worked fine !");
                  	}
                  
                  	public void lancer() {
                  		String[] args = new String[0];
                  		main(args);
                  	}
                  }
                  

                  Comme ça ça marche, on garde la même méthode main, et le code est quasi pas modifié ( on rajoute extends Launchable et une méthode lancer() )

                  Merci beaucoup de ton aide. :)



                  • Partager sur Facebook
                  • Partager sur Twitter

                  Méthodes d'un générique

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown