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

Langage Java Discussion :

Récupérer le type parametrant un paramètre générique


Sujet :

Langage Java

  1. #1
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut Récupérer le type parametrant un paramètre générique
    Soit les classes suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class Base<T> {
     
      T id;
      public T getId() {
        return id;
      }
      public void setId(T id) {
        this.id = id;
      }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Generique<U,T extends Base<U>> {
     
      Base<U> laBase;
     
      public void setLaBase(Base<U> laBase) {
        this.laBase = laBase;
      }
     
      public U getBaseId(){
        return laBase.getId();
      }
     
    }
    et deux classes: Machin extends Base<MonObjet> et MachinTruc extends Generique<MonObject,Machin>U et T sont redondant, toute l'information sur U est déjà présente dans T. Je voudrais donc pouvoir faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class MachinTruc extends Generique<Machin>
    mais je n'arrive pas à trouver comment déclarer Generique pour demander au compilateur d'extraire U à partir de T :/ Je ne sais même pas si c'est possible...



    Pour la petite histoire, j'ai déjà en réalité une classe
    Generique<T extends BaseString> mais je me retrouve sur un cas où il faudrait typer avec un BaseInteger, donc je voudrait refactorer la déclaration vers Base<> pour accepter plus large, mais si possible en n'ajoutant pas un paramètre générique car cela rendrait l'aval incompilable sans modif. Et des sous classes de Generique, on en a des dixaines dans différents projets . L'alternative c'est d'introduire une super classe qui reprends tout le code actuel:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class SuperGenerique<U,T extends Base<U>> {
     
      Base<U> laBase;
     
      public void setLaBase(Base<U> laBase) {
        this.laBase = laBase;
      }
     
      public U getBaseId(){
        return laBase.getId();
      }
     
    }
    et changer generique en

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public class Generique<T extends BaseString> extends SuperGenerique<String,T>
    Mais je voudrait éviter de créer cette classe en carton qui ne sert qu'à éviter le refactoring en aval

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    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 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    A quoi sert "T" dans ta classe "Generique" ? Tu ne l'utilise pas dans ton code.

    Autant faire directement ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Generique<U> {
     
      Base<U> laBase;
     
      public void setLaBase(Base<U> laBase) {
        this.laBase = laBase;
      }
     
      public U getBaseId(){
        return laBase.getId();
      }
     
    }

    a++

  3. #3
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    D'abord c'est une exemple, la classe réelle est bien plus complexe utilise le T dans ses interaction. Voilà un meilleur example

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Generique<U,T extends Base<U>> {
     
      T laBase;
     
      public void setLaBaseT laBase) {
        this.laBase = laBase;
      }
     
      public U getBaseId(){
        return laBase.getId();
      }
     
    }
    Le code existant est fait grosso modo


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Generique<T extends BaseString> {
     
      T laBase;
     
      public void setLaBaseT laBase) {
        this.laBase = laBase;
      }
     
      public String getBaseId(){
        return laBase.getId();
      }
     
    }
    Et je dois le refactorer en un truc genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Generique<T extends Base<?????>> {
     
      T laBase;
     
      public void setLaBaseT laBase) {
        this.laBase = laBase;
      }
     
      public ????? getBaseId(){
        return laBase.getId();
      }
     
    }
    en ayant les appelant qui travaillaient avec une sous classe de BaseString toujours capables de faire


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String id = laSousClassDeGenerique.getBaseId();

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    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 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Il faudrait voir le code exact, mais as-tu réellement besoin de paramétrer le type de Base ?

    [edit] Soit tu as besoin de paramétrer U et T et dans ce cas là tu dois obligatoirement utiliser deux types paramétrés.
    Soit tu as uniquement besoin de paramétrer U en utilisant un Base<U> sans plus de détail...


    a++

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

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Tu veux faire ça ? :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class Generique<T extends Base<U>, U> {
     
    	  T laBase;
     
    	  public void setLaBase(T laBase) {
    	    this.laBase = laBase;
    	  }
     
    	  public U getBaseId(){
    	    return laBase.getId();
    	  }
    	}
    Tu passes ton objet T qui étend Base<U> et tu peux récupérer U...


    Et tu l'appelles comme ça
    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
     
    public static void main(String[] args){
    		  Base<String> bString = new Base<String>(){
     
    			@Override
    			public String getId() {
    				return "String";
    			}
     
    		  };
     
    		  Generique<Base<String>, String> myGen = new Generique<>();
    		  myGen.setLaBase(bString);
    		  myGen.getBaseId();
    	  }

    Et oui, dans la déclaration, il FAUT les deux types paramétrés... Mais il y a des astuces pour n'avoir besoin que d'un seul...

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

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    La méthode pour n'en déclarer qu'un seul :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public interface GenericInterface<T extends Base<U>, U> {
     
    	public void setLaBase(T laBase);
     
    	public U getBaseId();
    }
    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
     
    public class Generique<U> implements GenericInterface<Base<U>, U> {
     
    	Base<U> laBase;
     
    	@Override
    	public void setLaBase(Base<U> laBase) {
    		this.laBase = laBase;
     
    	}
     
    	@Override
    	public U getBaseId() {
    		return laBase.getId();
    	}
     
    	public static void main(String[] args) {
    		Base<String> bString = new Base<String>() {
     
    			@Override
    			public String getId() {
    				return "String";
    			}
     
    		};
     
    		Generique<String> myGen = new Generique<>();
    		myGen.setLaBase(bString);
    		String myStr = myGen.getBaseId();
    	}
     
    }

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    ok, je vois que ce n'est pas possible malheureusement, j'avais espéré avoir raté une spécificité des generiques qui m'aurait aidé. Finalement après analyse du code interne à la classe, j'ai pu trouver une pirouette pour n'avoir pas besoin de connaitre les deux paramètre et j'ai pu me contenter de replacer generique<T extends BaseString> en <T extends <Base<?>>. En effet, en interne, tout retombe sur un String et, même si c'est moche à l'arrivée, avec un String.valueOf dans le code, on est capable de gérer toutes les autres bases.
    eulbobo, ta solution n'est pas envisageable, car j'ai besoin de savoir quelle sous classe concrète de Base<U> est utilisée, vu l'existence de méthodes retournant l'instance de Base<U>. Sans compter que ce n'est pas tant le fait d'avoir un seul type que je cherche, je cherche surtout à ce que ce type soit celui qui étends Base<???> car je cherche à remplacer <T extends BaseString> sans avoir à modifier les enfants déjà existant et très nombreux

    J'ai over simplifié l'exemple. En pratique c'est une classe abstraite générique chargée d'afficher une collection<T extends Base<String>> dans une grille. Elle contient tout ce qui concerne les headers, les traductions, les menus, récupération de l'objet sélection, envoi et réception d'event vers d'autres composants d'affichage pour synchronizer. Ensuite il y a une sous classe part type concret étendant Base<String> avec du code spécifique. Et je me suis retrouvé dans le cas où j'avais besoin d'une implémentation avec Base<Integer>. Et bien qu'il y a des méthodes qui devraient du coup ressortir des Integer au lieu de String, j'ai réussi à m'en sortir avec des conversion via valueOf. L'api en arrière plan d'affichage avait de toutes façons besoin de String

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

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Ha ben forcement, si y'a déjà une sous-classe avec du code spécifique, ça va devenir compliqué de faire du générique à plus haut niveau :p

    Je reste persuadé que ce que tu veux faire reste possible, mais je sais pas ce que tu as le droit de modifier (ou pas)

  9. #9
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    C'est surtout une question de logique plus que de droit. Je dois répondre à un problème mineur (changer la clé de String vers int dans un DTO), ça ne justifie pas de changer une 50aine de classes en contrebas

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

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Je dois répondre à un problème mineur (changer la clé de String vers int dans un DTO), ça ne justifie pas de changer une 50aine de classes en contrebas
    Ca apparaît pour toi comme un problème mineur, mais en soit, c'est surtout un problème de conception vis à vis de ce que TU veux faire aujourd'hui. Le code a été trop typé et du coup il n'est pas évolutif. Aujourd'hui, tu as besoin de le faire évoluer.
    Ca nous laisse deux possibilités :
    - soit tu modifies légèrement les 50 sous-classes existantes (en rajoutant des interfaces pour ne pas tout péter non plus) histoire de rendre tes objets évolutifs et pouvoir régler ton problème
    - soit tu mets une verrue qui résoudra temporairement et localement ton problème, en rajoutant à la complexité et la rigidité du système actuel


    J'ai vécu cette situation trop souvent, et trop souvent le chef m'a dit "Tu touches à rien, s'il faut faire une verrue pour que ça marche, fait une verrue". Ca s'est systématiquement retourné contre moi parce qu'il a fallu faire d'autres évolutions derrière. Et de verrues en verrues, j'ai créé des monstres...
    PLUS JAMAIS CA !
    Maintenant je dis merde et j'améliore le système pour me préserver de monstruosités (et pour préserver la santé mentale de ceux qui passeront derrière)


    Bref, quelle que soit la décision, bonne chance !

Discussions similaires

  1. [JAX-WS] Récupérer du XML dans un paramètre de type String
    Par verbose dans le forum Services Web
    Réponses: 0
    Dernier message: 01/07/2014, 17h19
  2. avoir le type du paramétre générique par réflexion
    Par al3alwa dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 22/01/2010, 13h36
  3. Passage d'un type procédure en paramètre par défaut
    Par Floverdoz dans le forum Langage
    Réponses: 1
    Dernier message: 22/07/2005, 17h48
  4. Récupérer le type de démarrage d'un service
    Par Nathan dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 09/04/2004, 15h07
  5. Type String* en paramètre...
    Par Invité dans le forum MFC
    Réponses: 4
    Dernier message: 24/02/2004, 19h48

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