IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Généricité sur les méthodes


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de domiq44
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 302
    Par défaut Généricité sur les méthodes
    Bonjour,

    Je suis en présence de code que je cherche à simplifier (c'est un « test case »).

    J'ai les 2 classes suivantes A et B :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class A {
    	private String ma1;
    	private String ma2;
    	private String ma3;
     
    	public String getMa1() {
    		return ma1;
    	}
     
    	public void setMa1(String ma1) {
    		this.ma1 = ma1;
    	}
     
    	public String getMa2() {
    		return ma2;
    	}
     
    	public void setMa2(String ma2) {
    		this.ma2 = ma2;
    	}
     
    	public String getMa3() {
    		return ma3;
    	}
     
    	public void setMa3(String ma3) {
    		this.ma3 = ma3;
    	}
     
    	@Override
    	public String toString() {
    		return "A [ma1=" + ma1 + ", ma2=" + ma2 + ", ma3=" + ma3 + "]";
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class B {
    	private String mb1;
    	private String mb2;
    	private String mb3;
     
    	public String getMb1() {
    		return mb1;
    	}
     
    	public void setMb1(String mb1) {
    		this.mb1 = mb1;
    	}
     
    	public String getMb2() {
    		return mb2;
    	}
     
    	public void setMb2(String mb2) {
    		this.mb2 = mb2;
    	}
     
    	public String getMb3() {
    		return mb3;
    	}
     
    	public void setMb3(String mb3) {
    		this.mb3 = mb3;
    	}
     
    	@Override
    	public String toString() {
    		return "B [mb1=" + mb1 + ", mb2=" + mb2 + ", mb3=" + mb3 + "]";
    	}
    }
    Et voici schématisé le programme principale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class App1 {
     
    	public static void main(String[] args) {
    		A a = new A();
    		a.setMa1("aaa111");
    		a.setMa2("aaa222");
    		a.setMa3("aaa333");
     
    		B b = new B();
    		b.setMb1("bbb111");
    		b.setMb2("bbb222");
    		b.setMb3("bbb333");
     
    		toto(a);
    		toto(b);
    	}
     
    	private static <T> void toto(T obj) {
    		if (obj instanceof A) {
    			System.out.println("lulu: " + lulu((A) obj));
    		}
    		if (obj instanceof B) {
    			System.out.println("lulu: " + lulu((B) obj));
    		}
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}
     
    	private static String lulu(A a) {
    		return a.getMa1();
    	}
     
    	private static String lulu(B b) {
    		return b.getMb2();
    	}
    }
    qui me retourne cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    lulu: aaa111
    class: domiq.generics.A
    value: A [ma1=aaa111, ma2=aaa222, ma3=aaa333]
    lulu: bbb222
    class: domiq.generics.B
    value: B [mb1=bbb111, mb2=bbb222, mb3=bbb333]
    Ce que je veux faire, c'est de rendre générique la méthode lulu().

    J'ai pensé à ça mais Eclipse me retourne une erreur car cela doit être faux.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class App2 {
     
    	public static void main(String[] args) {
    		A a = new A();
    		a.setMa1("aaa111");
    		a.setMa2("aaa222");
    		a.setMa3("aaa333");
     
    		B b = new B();
    		b.setMb1("bbb111");
    		b.setMb2("bbb222");
    		b.setMb3("bbb333");
     
    		toto(a);
    		toto(b);
    	}
     
    	private static <T> void toto(T obj) {
    		System.out.println("lulu: " + lulu(obj));          // <== ERREUR !!! ???
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}
     
    	private static <T extends A> String lulu(T a) {
    		return a.getMa1();
    	}
     
    	private static <T extends B> String lulu(T b) {
    		return b.getMb2();
    	}
    }
    L'erreur est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Bound mismatch: The generic method lulu(T) of type App2 is not applicable for the arguments (T). The inferred type T 
     is not a valid substitute for the bounded parameter <T extends A>
    Est-ce que quelqu'un peut m'aider ?
    Merci.

  2. #2
    Membre Expert
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    private static <T> void toto(T obj) {
    		System.out.println("lulu: " + lulu(obj));          // <== ERREUR !!! ???
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}
    Dans cette méthode, tu dis "je passe un objet d'un type inconnu à ma méthode". Toi tu sais que tu y passe une instance de A ou de B, mais le compilateur quand il lit ça, il interprète ça comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private static void toto(Object obj)
    Du coup, quand après tu essayes de le passer dans une méthode qui doit étendre A, forcement ça devient plus compliqué (il te demanderai un cast explicite si tu passais un Object, comme dans ton code plus haut)

    Ton autre méthode que déclares comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	private static <T extends A> String lulu(T a)
    Est interprétée comme ceci au final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	private static String lulu(A a)
    D'où le blocage. Tu as un Object, pas un A


    Pour aller un peu plus loin, quand tu écris : void <T extends A> String lulu(T a), ça veut dire que tu as une classe inconnue nommée T qui étend A. Mais si dans une autre fonction tu as aussi un void <T> String lulu(T a), ca ne sera pas forcement la même classe.
    Pour s'assurer que la classe décrite par ton T soit la même dans tout ton code, il faut le définir au niveau de la classe.

    Et il y a un twist :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class MaClasse<T extends Thread>{
     
        void faitDesTrucs(T valeur) throws SQLException{ // ici, on veut une instance d'un objet qui étend Thread
            valeur.getName(); // méthode de Thread
        }
     
        <T extends Closeable>  void fermeToi(T close) throws IOException{ 
        		// le T défini ici n'a rien à voir avec le type défini dans la classe
        	close.close(); // méthode de closeable
        }
    J'espere que c'est clair

  3. #3
    Membre éclairé Avatar de domiq44
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 302
    Par défaut
    Merci
    Citation Envoyé par eulbobo Voir le message
    eulbobo
    pour ta réponse.

    Je comprends ce que tu me dis.

    Mais est-il possible de faire, dans la méthode toto(), un appel à la méthode lulu(), qui soit propre à A ou propre à B, sans faire appel à instanceof ?

    C'est-à-dire, sans avoir à faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	private static <T> String lulu(T obj) {
    		String value = null;
    		if (obj instanceof A) {
    			value = ((A) obj).getMa1();
    		}
    		if (obj instanceof B) {
    			value = ((B) obj).getMb2();
    		}
    		return value;
    	}
    Oui, j'ai bien compris le twist. Et il est vrai que je ne l'avais pas vu. Donc merci.

  4. #4
    Membre Expert
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Par défaut
    Si tes objets n'ont aucun lien hiérarchique non

    Mais rien ne t'empêche d'avoir des signatures de méthodes spécifiques pour ce qui a besoin de l'être :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
             private static  void toto(A obj) {
    	        System.out.println("lulu: " + obj.getMa1());
    		blabla(obj);
    	}
     
            private static  void toto(B obj) {
    	        System.out.println("lulu: " + obj.getMb2());
    		blabla(obj);
    	}
     
           private static <T> void blabla(T obj) {
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}

    Après, si ta méthode lulu n'est là que pour renvoyer une valeur spécifique, vise l'interface !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public interface ILulu{
         String getLulu();
         setLulu(String lulu);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    public class A implements ILulu{
    	private String ma1;
    	private String ma2;
    	private String ma3;
     
    	public String getMa1() {
    		return ma1;
    	}
     
    	public String setMa1(String ma1) {
    		this.ma1 = ma1;
    	}
     
         public String getLulu(){
               return getMa1();
         }
         public setLulu(String lulu){
              setMa1(lulu);
         }
    Pareil pour B

    Et ensuite, tu as ton code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    public static void main(String[] args) {
    		A a = new A();
    		a.setMa1("aaa111");
    		a.setMa2("aaa222");
    		a.setMa3("aaa333");
     
    		B b = new B();
    		b.setMb1("bbb111");
    		b.setMb2("bbb222");
    		b.setMb3("bbb333");
     
    		toto(a);
    		toto(b);
    	}
     
    	private static <T extends ILulu> void toto(T obj) {
    		System.out.println("lulu: " + lulu(obj));
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}
     
    	private static <T extends ILulu> String lulu(T a) {
    		return a.getLulu();
    	}
    Ou sans les générics qui n'apportent rien ici

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    public static void main(String[] args) {
    		A a = new A();
    		a.setMa1("aaa111");
    		a.setMa2("aaa222");
    		a.setMa3("aaa333");
     
    		B b = new B();
    		b.setMb1("bbb111");
    		b.setMb2("bbb222");
    		b.setMb3("bbb333");
     
    		toto(a);
    		toto(b);
    	}
     
    	private static void toto(ILulu obj) {
    		System.out.println("lulu: " + lulu(obj));
    		System.out.println("class: " + obj.getClass().getName());
    		System.out.println("value: " + obj.toString());
    	}
     
    	private static String lulu(ILulu a) {
    		return a.getLulu();
    	}

  5. #5
    Membre éclairé Avatar de domiq44
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 302
    Par défaut
    Merci encore eulbobo pour ta réponse.

    En fait le programme a été schématisé afin de mettre en évidence les problèmes.
    Les méthodes sont bien plus complexes et ne font pas qu'afficher du texte.
    Donc KO pour la dernière méthode avec l'interface.

    Mais je regarde ta méthode avec l'utilisation de signatures de méthodes spécifiques pour ce qui a besoin de l'être...

  6. #6
    Membre éclairé Avatar de domiq44
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 302
    Par défaut
    On revient hélas au point de départ

    C'est-à-dire, comment appeler, à partir d'une méthode générique, une méthode propre à A et/ou une méthode propre à B ?

    Je pense qu'il faut absolument passer par l'utilisation commune de instanceof et de cast.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    	private static void toto(A obj) {
    		System.out.println("toto> value=" + obj.getMa1());
    		lulu(obj);
    	}
     
    	private static void toto(B obj) {
    		System.out.println("toto> value=" + obj.getMb2());
    		lulu(obj);
    	}
     
    	private static <T> String lulu(T obj) {
    		String value = null;
    		if (obj instanceof A) {
    			bidon((A) obj);
    		}
    		if (obj instanceof B) {
    			bidon((B) obj);
    		}
    		return value;
    	}

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Optimisation sur les méthodes vides ?
    Par ngryman dans le forum EDI/Outils
    Réponses: 3
    Dernier message: 30/09/2008, 16h21
  2. Sources sur les méthodes agiles
    Par __Ez__ dans le forum Méthodes Agiles
    Réponses: 1
    Dernier message: 25/05/2008, 10h29
  3. Erreurs sur les méthodes ApplicationClass et Application
    Par Invité dans le forum Windows Forms
    Réponses: 5
    Dernier message: 29/04/2008, 17h39
  4. PDT et autocompletion, liens sur les méthodes
    Par Tanebisse dans le forum Eclipse PHP
    Réponses: 1
    Dernier message: 10/12/2007, 17h34
  5. Question sur les méthodes abstraites
    Par nmathon dans le forum Delphi
    Réponses: 3
    Dernier message: 15/06/2006, 20h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo