Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 9 sur 9
  1. #1
    Candidat au titre de Membre du Club
    Profil pro
    Inscrit en
    décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : décembre 2006
    Messages : 71
    Points : 11
    Points
    11

    Par défaut Utilisation des generics

    Bonjour a tous,

    je cherche à créer une structuration de class manipulant des objets qui peuvent être des doubles ou des complexes.

    Afin de ne pas écrire plusieurs fois les class Point2D, Point3D, vector, matrix... qui manipule soit des doubles soit des complexes j’aimerai utiliser les generics.

    J'ai donc créé des class (Point2D, Point3D, vector, matrix...) manipulant des :
    MyNumber<>

    MyDouble et MyComplex sont des MyNumber<>

    Or j'ai un problème à la compilation comme définie en suivant:

    Code :
    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
    37
    38
    39
    40
    41
    42
    public interface Numeric<Type> extends Comparable<Type>{
    	public abstract Type atan2(Type v);
    	public abstract Type atan2(double d);
    	public abstract Type sin();
    	public abstract Type sinh();
    	public abstract Type cos();
    	public abstract Type cosh();
    	public abstract Type tan();
    	public abstract Type add(Type v);
    	public abstract Type add(double d);
    	public abstract Type sub(Type v);
    	public abstract Type sub(double d);
    	public abstract Type cube();
    	public abstract Type sqrt();
    ...
    }
    
    public abstract class MyNumber<T> extends Number implements Numeric<T>{...}
    public class MyDouble extends MyNumber<MyDouble> {...}
    public class MyComplex extends MyNumber<MyComplex> {...}
    
    
    public class Triedre<Type extends MyNumber<Type>>{
    ...
    	private Type a;
    	private Type b;
    	private Type c;
    	
    	public Triedre(Type a, Type b, Type c) {
    		this.a = a;
    		this.b = b;
    		this.c = c;
    	}
    
    	public Triedre(double a, double b, double c) {
    		this.a = new MyDouble(a); // erreur de compilation
    		this.b = new MyDouble(b); // erreur de compilation
    		this.c = new MyDouble(c); // erreur de compilation
    	}
    ...
    }
    en résumé :
    - MyDouble est de type "MyNumber<MyDouble>"
    - le type "Type" dans la class Triedre est de type "MyNumber<Type>"

    comment faire en sorte que les types soit compatible?

    Merci d'avance pour votre support.
    Sébastien.

  2. #2
    Modérateur

    Inscrit en
    septembre 2004
    Messages
    9 733
    Détails du profil
    Informations forums :
    Inscription : septembre 2004
    Messages : 9 733
    Points : 16 076
    Points
    16 076

    Par défaut

    Une double est un double, il n'a pas besoin de paramètre et ne peut donc pas avoir de paramètre. MyDouble doit être de type MyDouble sans paramètre.
    De même MyComplex ne doit pas avoir de paramètre.

    Les deux doivent répondre à une interface commune pour addition, etc. Donc interface MyNumber, implémentée par les deux. Mais il va lui falloir un paramètre.

    Parce que, pour l'addition, supposons que ça ressemble à ça :

    Code :
    1
    2
    3
    public interface MyNumber {
      MyNumber add(MyNumber other);
    }
    Du coup MyDouble ressemblera à

    Code :
    1
    2
    3
    4
    5
    6
    public class MyDouble implements MyNumber {
      double value;
      MyDouble add(MyNumber other) {
        double newValue = this.value + other./* ? là on peut rien faire de MyNumber other*/;
      }
    }
    Ça ne va pas. MyDouble.add() doit prendre des MyDouble en paramètre et donner des MyDouble en sortie.

    Comme ça :

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public interface MyNumber<T extends MyNumber<T>> {
      T add(T other);
    }
     
    public class MyDouble implements MyNumber<MyDouble> {
      double value;
      MyDouble add(MyDouble other) {
        double newValue = this.value + other.value;
     
        MyDouble newDouble = new MyDouble();
        newDouble.value = newValue;
        return newDouble;
      }
    }
    Et voilà.

    Pour les rendre comparables, ajouter :

    Code :
    1
    2
    3
    public interface MyNumber<T extends MyNumber<T>> extends Comparable<T> {
      ...
    }
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher du poisson, il videra le lac et au bout de deux ans son village ne mangera plus jamais.
    Partagez vos connaissances, mais aussi comment s'en servir.

  3. #3
    Candidat au titre de Membre du Club
    Profil pro
    Inscrit en
    décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : décembre 2006
    Messages : 71
    Points : 11
    Points
    11

    Par défaut

    Bonsoir thelvin,

    Je suis d'accord avec toi et je pense que ce que j'ai posté dans mon premier message répond à se que tu dis.

    Toutefois, j'ai un problème lorsque je veux utiliser MyDouble et MyComplex dans une class utilisant le père de ses deux class (MyNumber<T>).

    Soit le type "Type" qui extends "MyNumber<Type>"

    pourquoi n'est il pas possible de faire ce qui suit?
    Type a = new MyDouble();

    Or MyDouble est bien du type MyNumber<T>

  4. #4
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 311
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 311
    Points : 21 540
    Points
    21 540

    Par défaut

    Salut,

    Citation Envoyé par <_oodTi96Tiboo_> Voir le message
    Soit le type "Type" qui extends "MyNumber<Type>"

    pourquoi n'est il pas possible de faire ce qui suit?
    Type a = new MyDouble();

    Or MyDouble est bien du type MyNumber<T>
    D'une part les normes de codages recommande d'utiliser une seule lettre en majuscule pour éviter les confusions. Bref tu devrais utiliser T à la place de Type.


    Ensuite non ce n'est pas la même chose, justement parce que le type exact des paramètres paramétrés n'est pas connu lors de la compilation de ta classe.

    Lorsque tu compiles ceci :
    Code :
    class Triedre<T extends MyNumber<T>> {
    Tu sais que le type T étends MyNumber<T>, mais c'est tout. Tu ne peux pas en conclure autre chose ou lui attribuer un type fixe.

    En effet lorsque tu associes un objet de type "MyDouble" dans un objet de type T, tu casses la généricité.

    En effet cela marchera lorsque tu utiliseras un new Triedre<MyDouble>, mais que se passera-t-il lorsque tu instancieras un new Triedre<MyComplex> ?
    En effet T devrait correspondre alors à MyComplex, mais tu met un MyDouble dedans ce qui est impossible puisqu'il s'agit d'un type parent.
    C'est comme si tu écrivais ceci :
    Code :
    MyComplex m = new MyDouble(0);



    Bref lorsque tu écris une classe générique, le type précis est inconnu et tu ne peux pas présumer qu'il s'agira d'un type précis. Sinon les generics sont inutiles...


    a++

  5. #5
    Candidat au titre de Membre du Club
    Profil pro
    Inscrit en
    décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : décembre 2006
    Messages : 71
    Points : 11
    Points
    11

    Par défaut

    Bonjour AdiGuda,

    Merci pour ta réponse. Elle confirme mes dernières recherches sur les génériques.

    De ce fait, j'ai revu mon code hier soir. J'ai ajouté un constructeur à ma class abstract MyNumber prenant un "double" qui sera implémenté dans le class irritant de MyNumber:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public abstract class MyNumber<T> extends Number implements Numeric<T>{
     
    public MyNumber(){
    	this(0);
    }
     
    public MyNumber(double d) {}	// must be re-implemented by children
    ...
    Toutefois lors que je tente d'utiliser ce constructeur dans la class "Triedre", on me dit qu'il n'est pas possible d'instancier le type "Type".

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Triedre<Type extends MyNumber<Type>>{
    	private Type a;
    	private Type b;
    	private Type c;
    
    	public Triedre(double a, double b, double c) {
    		this.a = new Type(a);	// error : Cannot instantiate the type Type
    		this.b = new Type(b);	// error : Cannot instantiate the type Type
    		this.c = new Type(c);	// error : Cannot instantiate the type Type
    	}
    	...
    }
    Peux tu me dire pourquoi le construteur "MyNumber(double d)" n'est pas visible dans la class Triedre?

    PS: Merci pour le rappel des conventions de nommage des generics. Si j'ai utiliser <Type> au le de <T> c’était pour vérifier qu'il n'y avait pas de confusion entre les différents type generic.

  6. #6
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 311
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 311
    Points : 21 540
    Points
    21 540

    Par défaut

    Citation Envoyé par <_oodTi96Tiboo_> Voir le message
    J'ai ajouté un constructeur à ma class abstract MyNumber prenant un "double" qui sera implémenté dans le class irritant de MyNumber:
    Les constructeurs ne s'héritent pas, et ne peuvent donc pas être "implémenté" par des classes filles...


    Citation Envoyé par <_oodTi96Tiboo_> Voir le message
    Toutefois lors que je tente d'utiliser ce constructeur dans la class "Triedre", on me dit qu'il n'est pas possible d'instancier le type "Type".
    Normal : le type "Type" n'existe pas !!!


    En fait tu veux faire ceci :
    Mais c'est quoi T ?
    Cela peut être un MyDouble, un MyComplex... ou n'importe quelles autres classes héritant de MyNumber !
    Le compilateur ne peut pas décider de cela à ta place !


    Dis-toi bien qu'à l'intérieur du code d'une classe Generics, le type exact de T est inconnu. Donc le compilateur ne peut pas effectuer certaines opération comme new T() ou T.class...
    (enfin en vrai il pourrait le faire, mais cela aboutirait à du code non-typesafe, ce qui va à l'encontre même des Generics)



    Bref tu ne peux pas faire cela !
    Soit tu fait quelque chose de fortement typé :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Triedre {
    	private MyDouble a;
    	private MyDouble b;
    	private MyDouble c;
     
    	public Triedre(double a, double b, double c) {
    		this.a = new MyDouble(a);
    		this.b = new MyDouble(b);
    		this.c = new MyDouble(c);
    	}
    }
    Soit tu fait quelque chose de complètement générique :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Triedre<T extends MyNumber<T>>{
    	private T a;
    	private T b;
    	private T c;
     
    	public Triedre(T a, T b, T c) {
    		this.a = a;
    		this.b = b;
    		this.c = c;
    	}
    }
    Mais tu ne peux pas faire les deux.


    A la rigueur, tu peux te faire deux petite méthode factory pour simplifier la création de Triedre<MyDouble> ou Triedre<MyComplex> :
    Code :
    1
    2
    3
    4
    5
    6
    7
    	public static Triedre<MyDouble> newDouble(double a, double b, double c) {
    		return new Triedre<MyDouble>(new MyDouble(a), new MyDouble(b), new MyDouble(c));
    	}
     
    	public static Triedre<MyComplex> newComplex(double a, double b, double c) {
    		return new Triedre<MyComplex>(new MyComplex(a), new MyComplex(b), new MyComplex(c));
    	}


    a++

    PS : Tant que tu n'encapsules pas les classes il n'y a aucun conflit dans les noms des paramètres Generics. C'est au contraire le fait d'utiliser un nom de classe qui apporte de la confusion dans la lecture du code...

  7. #7
    Candidat au titre de Membre du Club
    Profil pro
    Inscrit en
    décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : décembre 2006
    Messages : 71
    Points : 11
    Points
    11

    Par défaut

    j'aurai une petite nuance à ta réponse. Mais peut être que j'ai mal compris un truc.

    Je suis Ok sur le fait que "Type" n'est pas spécifiquement connu par la compilateur.

    Mais le compilateur sait qu'il extends MyNumber non?

    or si on déclare un constructeur dans MyNumber il doit pouvoir le voir non?

  8. #8
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 311
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 311
    Points : 21 540
    Points
    21 540

    Par défaut

    Citation Envoyé par <_oodTi96Tiboo_> Voir le message
    Mais le compilateur sait qu'il extends MyNumber non?
    Oui, et c'est tout ce qu'il sait.
    Du coup tu peux utiliser les méthodes définis dans MyNumber sur les objets de type T.

    Citation Envoyé par <_oodTi96Tiboo_> Voir le message
    or si on déclare un constructeur dans MyNumber il doit pouvoir le voir non?
    Non : les constructeurs ne n’héritent pas...


    a++

  9. #9
    Candidat au titre de Membre du Club
    Profil pro
    Inscrit en
    décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : décembre 2006
    Messages : 71
    Points : 11
    Points
    11

    Par défaut

    Oui effectivement j’oublie toujours ce fait.

    Merci pour tes conseils. Je constate que tu est toujours aussi magnanime malgré les années. Bonne continuation.

    Sébastien.

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •