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 :

Cherche recommandations/normes d'écriture pour Java 1.6


Sujet :

Langage Java

  1. #41
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Non, à part le contrôle à la compilation, cela n'apporte rien. C'est comme les generics : à part mettre des marqueurs intéressant à la compilation, cela n'apporte rien
    Pas d'accord avec ça. D'abord, les "marqueurs" à la compilation sont particulièrement intéressants car ils permettent d'effectuer un contrôle très rigoureux du typage, ce qui n'est pas du tout négligeable, mais en plus, les generics permettent d'éviter de nombreux cast (presque tous en fait, à l'exception des tableaux) qui ont un coût important en runtime.

  2. #42
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par benwit Voir le message
    Et à ce propos, dans les cas où null est indésirable, est-ce selon vous une bonne pratique de mettre assert(value != null) ?
    Selon moi, ça dépend du contexte. Les use cases sont les suivants:
    • Dans une méthode interne à ta librairie où ton projet qui prend en paramètre une référence à un objet qui, un fois le code terminé ne doit théoriquement jamais pouvoir être null, il est préférable d'utiliser un assertion qui sera purement et simplement supprimée du code dans le livrable mais qui te permet de savoir qu'il y a un problème à régler avant de fournir le livrable final pendant que tu fais tes tests.
    • Dans une méthode exposée d'une manière une d'une autre, une API où dont les paramètres sont conditionnés par une saisie de l'utilisateur du soft par exemple, et qui ne doit pas accepter les null, il faut commencer par tester la référence et envoyer une NullPointerException.
    • Si la méthode peut accepter les null parce que ça correspond à un cas d'utilisation, pas de problèmes.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par Yomhgui Voir le message
    Dans une archive donnée, par nature recompilée en intégralité à chaque fois, il y a quand même tout un tas de cas où on peut savoir en analysant la portée des éléments s'il sont susceptibles d'être appelés en dehors de la librairie.
    Le seules ou t'a la garantie qu'ils seront pas appelé de l'extérieur, ce sont les private. Pour le reste, t'as zéro garantie. Je peux très bien avoir deux jars séparés qui ont des classes dans le même package.

  4. #44
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Le seules ou t'a la garantie qu'ils seront pas appelé de l'extérieur, ce sont les private. Pour le reste, t'as zéro garantie. Je peux très bien avoir deux jars séparés qui ont des classes dans le même package.
    Mais est-ce que dans ce cas, il peut y avoir des appels d'une méthode package protected depuis un jar vers un autre ? J'avoue n'avoir jamais fait ce genre d'essais ! Ca me parait délicat car dans ce cas la notion de package protected n'a que peut d'intérêt. en plus, il serait aisé de créer un package sun.com et d'appeler des méthodes ayant une portée à priori limitée du JDK (si je me rappel bien, seul les packages commençant par java et javax ne sont pas autorisés ??). Tu es sur qu'il n'y a pas une mécanique de protection (à base de ClassLoader ???) pour éviter ce genre de choses ?

  5. #45
    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
    Citation Envoyé par Yomhgui Voir le message
    Tu es sur qu'il n'y a pas une mécanique de protection (à base de ClassLoader ???) pour éviter ce genre de choses ?
    Il faut sceller le package (ou carrément tout le jar) via le manifest. Cela obligera la JVM à n'accepter que des classes de la même archive, et provoquera une exception à l'exécution le cas échéant.

    Plus d'info : Sealing Packages within a JAR File

    a++

  6. #46
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    Pas d'accord avec ça. D'abord, les "marqueurs" à la compilation sont particulièrement intéressants car ils permettent d'effectuer un contrôle très rigoureux du typage, ce qui n'est pas du tout négligeable, mais en plus, les generics permettent d'éviter de nombreux cast (presque tous en fait, à l'exception des tableaux) qui ont un coût important en runtime.
    D'une part, je n'ai pas dit que les marqueurs à la compilation étaient inutiles (d'ailleurs, j'en use et abuse), d'autre part je viens de vérifier le binaire d'un fichier .class avec generics et du même fichier sans generics avec juste un cast en plus : le cast est bel et bien effectué dans les deux cas.

    Pour info, voici les tests. (Le .class du second est bien entendu plus long du fait de l'utilisation des generics.)

    Sans generics :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class Test {
    	public static void main (String[] args) {
    		List l = new ArrayList();
    		l.add("Hello World");
    		String s = (String)l.get(0);
    		System.out.println(s);
    	}
    }
    Avec generics :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package test;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class Test {
    	public static void main (String[] args) {
    		List<String> l = new ArrayList<String>();
    		l.add("Hello World");
    		String s = l.get(0);
    		System.out.println(s);
    	}
    }

  7. #47
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Il faut sceller le package (ou carrément tout le jar) via le manifest. Cela obligera la JVM à n'accepter que des classes de la même archive, et provoquera une exception à l'exécution le cas échéant.

    Plus d'info : Sealing Packages within a JAR File

    a++
    Opération que je ne faisais pas jusqu'ici et à laquelle je ne me suis jamais intéressé. Merci beaucoup pour cette info que je vais mettre à profit dès que possible.

    Ceci dit, comme je travaille essentiellement en environnement OSGi, je ne suis pas sur que la question se pose dans les même termes puisque la mécanique de protection est beaucoup plus développée dans ce cas. Je vais regarder ce cas de près.

  8. #48
    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
    Citation Envoyé par Yomhgui Voir le message
    Ceci dit, comme je travaille essentiellement en environnement OSGi, je ne suis pas sur que la question se pose dans les même termes puisque la mécanique de protection est beaucoup plus développée dans ce cas. Je vais regarder ce cas de près.
    Au passage, puisque tu parles d'OSGi, le système de module de Java 7 devrait être compatible avec OSGi...

    Cela devrait rajouter un niveau de visibilité "module"

    a++

  9. #49
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par dingoth Voir le message
    D'une part, je n'ai pas dit que les marqueurs à la compilation étaient inutiles (d'ailleurs, j'en use et abuse),
    Tu as bien raison d'en user à mon avis ! Et de me coté, je n'interprète pas ta vision comme une déclaration d'inutilité. Je suis juste en désaccord avec l'importance que tu leur accorde dans "cela n'apporte rien". en effet, les generics ne se limitent pas à leur utilisation dans les conteneurs du JDK que tu as utilisés pour le test ci-dessous et qui rentrent justement dans le cas que j'évoquais dans lequel on ne peut pas se passer des casts.

    En effet, pour des raisons de compatibilité ascendante entre Java 1.4.x et Java 1.5.x, et qui sont expliquées en détail sur le site de Sun, on ne peut pas faire une allocation d'un tableau de manière générique:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public <T> T[] createArray(int size) {
        return new T[size];
    }
    Ca ne marche pas .

    C'est pour ça par exemple que la méthode List.toArray() retourne un Object[] alors qu'on peut créer soit même un tableau et le passer à la méthode List.toArray(T[]).

    Donc, comme à un endroit ou a un autre dans une collection, il y a souvent un tableau, dont l'allocation est gérée par la collection elle-même, il n'est pas, comme on pourrait le croire, de type T[], mais de type Object[]. Vérifie dans le code de ArrayList par exemple.

    Par conséquent, quand tu fais un get(), il y a effectivement un cast pour te retourner un objet du type T attendu. Il y a quand quand même déjà une grosse différence entre une List et une List<T>. C'est que dans la List (tout court), il est possible de mettre n'importe quel Object, ce qui fait que quand tu relis les éléments dans la liste, tu peux avoir un ClassCastException lorsque tu veux obtenir les objets dans le type que tu attends (si une autre développeur a mal utilisé ta collection par exemple). Ceci est impossible avec une List<T> puisque les add n'accepterons dès la compilation que des objets qui sont strictement du type attendu (avant de dégradé le typage en les mettant dans le tableau interne...).

    Maintenant, ce problème ne concerne que les tableaux. Je te fais un petit exemple que tu pourras tester pour t'en convaincre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    package p;
     
    public interface I {
     
    	void invoke();
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package p;
     
    public class CI1 implements I {
     
    	/**
             * {@inheritDoc}
             */
    	@Override
    	public void invoke() {
    		System.out.println("I am a CI1");
    	}
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package p;
     
    public class CI2 implements I {
     
    	/**
             * {@inheritDoc}
             */
    	@Override
    	public void invoke() {
    		System.out.println("I am a CI2");
    	}
     
    }
    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
    package p;
     
    public class C<T extends I> {
     
    	private final T _i;
     
    	public C(final T i) {
    		_i = i;
    	}
     
    	public T get() {
    		return _i;
    	}
     
    }
    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
    package p;
     
    public class Main {
     
    	public static void main(final String[] args) {
     
    		final C<?>[] cs = {
    			new C<CI1>(new CI1()),
    			new C<CI2>(new CI2()),
    			new C<CI1>(new CI1()),
    		};
     
    		for (final C<?> c : cs)
    			c.get().invoke();
     
    	}
     
    }
    Vérifie le bytecode et tu verras qu'il n'y a aucun cast de fait à aucun moment. Par contre le contrôle de type est très fort. Évidemment l'exemple est pour le moins simpliste et à prendre pour ce qu'il vaut. Mais ce genre d'approche permet de rendre certains éléments de code très très génériques et en même temps très sur quant au contrôle des types dès la compilation. D'où le très grand intérêt des generics à mon avis et en particulier de l'implémentation avec contrôle de "limites de types" qui en est faite dans le langage Java.

  10. #50
    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
    Citation Envoyé par Yomhgui Voir le message
    Vérifie le bytecode et tu verras qu'il n'y a aucun cast de fait à aucun moment. Par contre le contrôle de type est très fort.
    Non... Tu tombes bien car tu utilises une interface, et que le cast est inutile dans ton cas précis, surtout que tu utilises par la suite C<?> (sans typage fort justement).


    Les classes Generics conservent bien les casts à l'exécution, mais ils sont vérifié dès la compilation

    a++

  11. #51
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    Ton raisonnement est en outre faux, puisque je te parle du bytecode de Test, et toi tu me parles de tableaux de l'ArrayList. Prends une LinkedList si tu préfères : pas de trace de tableau, et le bytecode de Test ne changera pas (hormis ArrayList -> LinkedList) et contiendra toujours le cast.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    le package protected sert à limiter la vue aux classe du package, pas du jar. C'est pas une garantie de sécurité. Dans certains cas (librairies malfoutues) on est obligé comme ca d'injecter dans un package une classe "bridge" qui accède a des données que l'éditeur de la classe na pas jugé utile de rendre publiques, mais dont tu as besoin.

  13. #53
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Non... Tu tombes bien car tu utilises une interface, et que le cast est inutile dans ton cas précis, surtout que tu utilises par la suite C<?> (sans typage fort justement).


    Les classes Generics conservent bien les casts à l'exécution, mais ils sont vérifié dès la compilation

    a++
    Ben oui, il y a un C<?> puisque tout à la fin je mets différentes instances dans un tableau histoire de dire que on peut avoir comme ça des comportements polymorphes super chiadés mais c'est pour l'exemple. Le typage, dans les classes CI1 et CI2, il est fort, voilà !!! Non là vraiment tu chipotes

    Bon alors je la refais en plus simpliste:

    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
    package p;
     
    public class CC1<T> {
     
    	private final T _t;
     
    	public CC1(final T t) {
    		_t = t;
    	}
     
    	public T get() {
    		return _t;
    	}
     
    }
    Et le bytecode qui va avec:

    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
      // access flags 1
      // signature ()TT;
      // declaration: T get()
      public get()Ljava/lang/Object;
       L0
        LINENUMBER 12 L0
        ALOAD 0
        GETFIELD p/CC1._t : Ljava/lang/Object;
        ARETURN
       L1
        LOCALVARIABLE this Lp/CC1; L0 L1 0
        // signature Lp/CC1<TT;>;
        // declaration: p.CC1<T>
        MAXSTACK = 1
        MAXLOCALS = 1
    Bon j'ai juste mis la méthode get() qui est celle qui m'intéresse. Il n'y a pas de cast.

    Quelque chose d'équivalent mais sans genercis:

    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
    package p;
     
    public class CC2 {
     
    	private final Object _o;
     
    	public CC2(final String s) {
    		_o = s;
    	}
     
    	public String get() {
    		return (String)_o;
    	}
     
    }
    Et le bytecode du get():

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      // access flags 1
      public get()Ljava/lang/String;
       L0
        LINENUMBER 12 L0
        ALOAD 0
        GETFIELD p/CC2._o : Ljava/lang/Object;
        CHECKCAST java/lang/String
        ARETURN
       L1
        LOCALVARIABLE this Lp/CC2; L0 L1 0
        MAXSTACK = 1
        MAXLOCALS = 1
    Dans lequel il y bien un cast.

    Et dans tout ça, pas d'interfaces, même pas de borne explicite sur le type paramétré. Et puis je veux bien replacer dans l'exemple précédent l'interface par une classe abstraite mais je pense que le résultat sera le même.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Ton raisonnement est en outre faux
    ... Donc pas tant que ça en définitive puisque qu'il n'y a effectivement pas de cast. Par ailleurs, ton exemple utilisait une ArrayList donc je l'ai pris comme référence...

    Je vais quand même faire mes petites vérifs sur LinkedList parce que le cas que tu mentionnes me surprend.

    @+

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Le cast ne se fait pas au meme endroit. Dans les generics, ce sont les appelant qui font les cast. en effet, la même classe peut etre utilisé pour plein de types différents. Par contre, l'appelant connait normalement le type. Si il le connait pas (toujours paramétré) c'est redélégué plus haut, etc.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Machin<T> {
    T _t;
    T _t2;
    public T setT(T t){
       _t = t;
       return _t2;
    } 
    ....
    Machin<String> m = new Machin<String>();
    String s = m.setT("hello");
    et normalement l'équivalent de ça.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Machin {
    Object _t;
    Object _t2;
    public Object setT(Object t){
       _t = t;
       return _t2;
    } 
    ....
    Machin m = new Machin();
    String s = (String)m.setT("hello");

  15. #55
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Et oui, je me suis fait avoir comme un bleu.

    En effet, le comportement à de quoi surprendre mais effectivement, le cast existe, là où je n'avait pas regardé... Après que la référence ai été retournée, même si la méthode fait elle-même un cast explicite dans le type du paramètre, comme dans:

    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
    package p;
     
    public class CC3<T> {
     
    	private final Object _o;
     
        public CC3(final T t) {
        	_o = t;
        }
     
        public T get() {
        	return (T)_o;
        }
     
    }
    Il n'y a pas de cast dans le get() mais il y en a un dans le bytecode de chaque appelant. D'un autre côté, après réflexion, il peut quand même difficilement en être autrement.

    Mea culpa.

    Ceci dit, j'avoue ne pas saisir (pour l'instant) le pourquoi de la chose. Ce cast est quand même totalement inutile puisque le type est connu. Est-ce une conséquence des questions d'érésure où alors pour conserver le fonctionnement des "raw types" ???

    Enfin quoi qu'il en soit, ça n'enlève quand même rien à l'intérêt des genercis en termes de qualité de développement mais c'est vrai que sur les perfs, on pourra repasser. Dommage. Et ça valide au passage ce que tu disais, dingoth : aucun intérêt dans le bytecode !!

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    CE cast est nécessaire car les generics ne sont pas garanti en cas de mauvais programmeur. Le generics t'évitent simplement de devoir le mettre explicitement partout dans ton code, le compilo le faisant à ta place.

    Exemple simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    List<String> maList = ....;
    List l = maList; //warning compilateur
    l.add(new Integer(3));
    String s = maList.get(0); // sans un cast dans le bytecode, la jvm va être dans le caca pour gérer ça ;)

  17. #57
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    CE cast est nécessaire car les generics ne sont pas garanti en cas de mauvais programmeur. Le generics t'évitent simplement de devoir le mettre explicitement partout dans ton code, le compilo le faisant à ta place.

    Exemple simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    List<String> maList = ....;
    List l = maList; //warning compilateur
    l.add(new Integer(3));
    String s = maList.get(0); // sans un cast dans le bytecode, la jvm va être dans le caca pour gérer ça ;)
    Ouaip en effet, c'est bien un problème lié à la conservation des "raw types" et à la compatibilité avec d'anciennes versions du langage alors ? Ce problème que tu évoques ne pourrait pas se poser si l'utilisation d'un paramètre était obligatoire, où alors je ne vois pas de use case qui corresponde à ça.

    Ceci dit, il y a une conséquence de ça qui me chagrine fortement. En définitive, l'utilisation des genercis aurait même plutôt tendance à dégrader le byte code.

    Pour reprendre l'exemple que j'avais évoqué plus haut, celui avec I, CI1, CI2 et C. Dans cet exemple, de manière factuelle, l'utilisation de types paramétrés ne sert à rien. Par contre, quand on utilise C.get() : T qui retourne une référence du type paramétré dans C<T>, on se paye un cast alors que si on avait simplement utilisé un type I pour l'attribut de la classe C, on aurait eu le même comportement sans faire aucun cast en runtime cette fois.

    En effet, d'après ce que j'ai pu voir dans le byte code, même si on déclare un paramètre de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    interface I {}
     
    class C<T extends I> {
        private T _t;
    }
    dans le code compilé, l'attribut de _t de C n'est pas de type I (ce qui semblerait pourtant théoriquement possible) mais de type Object.

    Bon, au vu des (très grands) avantages en terme de contrôle de typage à la compilation, je continue à penser que ça vaut le coût de payer ce petit inconvénient, mais ça me semble quand même bien dommage.

    Je vais quand même revérifier ça par acquis de conscience...

    Bon, fausse alerte. Le type déclaré de l'attribut C._t est bien I, donc pas de problèmes de ce côté.

  18. #58
    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
    Citation Envoyé par Yomhgui Voir le message
    Ceci dit, j'avoue ne pas saisir (pour l'instant) le pourquoi de la chose. Ce cast est quand même totalement inutile puisque le type est connu.
    Le type n'est pas connu justement !!!

    Le "raw type" correspond au type de base de déclaration du generics. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class MaClass<T> { 
     // Le raw type de T est Object
    }
     
    class MaClass2<T extends Number> {
      // Le raw type de T est Number
    }
    Le raw-type correspond au type que tu utiliserais si la classe n'était pas paramétrée...



    Citation Envoyé par Yomhgui Voir le message
    Ceci dit, il y a une conséquence de ça qui me chagrine fortement. En définitive, l'utilisation des genercis aurait même plutôt tendance à dégrader le byte code.
    Non cela ne dégrade en rien le bytecode. Cela n'ajoute des casts que là où tu aurait dû les mettre.
    Par contre, si tout compile sans warning, cela te garantie qu'aucune ClassCastException ne viendra pourrir ton exécution


    Il y a plusieurs raisons à tout cela, dont la principale étant la compatibilité...
    Pour plus d'info : Les Generics ne sont pas des Templates comme les autres !

    a++

  19. #59
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Points : 90
    Points
    90
    Par défaut
    OK, ce sont bien les conclusions auxquelles j'étais arrivé (à la fin des fins !!!).

    Ce qui me surprend, c'est quand tu dis que le type n'est pas connu. De manière factuelle, si le type est connu lors de la compilation, il n'y a pas de raison qu'il ne le soit pas en runtime. C'est quand même bien dommage justement de ne pas pouvoir profiter du fait que l'on peut effectivement bénéficier du type checking pour résoudre le typage de manière déterministe et ne pas conserver ces données dans le code compilé !! Compatibilité ascendante, quand tu nous tiens...

    PS: en ce qui me concerne je n'accepte pas de code avec des "unchecked cast" (sauf cas particulier pourri où ça n'est pas possible de faire autrement évidemment), donc pas de warning.

    PS: La définition du raw type dans le spécification du langage:

    More precisely, a raw type is define to be either:

    * The name of a generic type declaration used without any accompanying actual type parameters.
    * Any non-static type member of a raw type R that is not inherited from a superclass or superinterface of R.
    PS3: Je me souviens d'avoir trouvé un article très intéressant sur la question de l'allocation des tableaux génériques (l'impossibilité de...) mais j'ai ma dose pour ce soir. Je tacherai de le remettre en référence ici demain.

  20. #60
    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
    Citation Envoyé par Yomhgui Voir le message
    C'est quand même bien dommage justement de ne pas pouvoir profiter du fait que l'on peut effectivement bénéficier du type checking pour résoudre le typage de manière déterministe et ne pas conserver ces données dans le code compilé !!
    Oui... mais 95% des fonctionnalités sont malgré tout présente

    Citation Envoyé par Yomhgui Voir le message
    Compatibilité ascendante, quand tu nous tiens...
    En même temps tu te voyais avec une API "Collections 2" incompatible avec l'API de Collections actuelles ???

    Citation Envoyé par Yomhgui Voir le message
    PS3: Je me souviens d'avoir trouvé un article très intéressant sur la question de l'allocation des tableaux génériques (l'impossibilité de...) mais j'ai ma dose pour ce soir. Je tacherai de le remettre en référence ici demain.
    Je n'ai plus en tête le problème exact... mais cela vient du fait que la vérification du typeage des Generics est fait à la compilation, alors que celui des tableau l'est à l'exécution.
    Tu peux te retrouver dans certains cas avec des erreurs bien bizarre...

    a++

Discussions similaires

  1. Cherche une API de report pour JAVA
    Par MaxLaMenaX dans le forum Documents
    Réponses: 6
    Dernier message: 10/04/2009, 08h54
  2. Cherche un outil de reporting comme BIRT pour Java
    Par tiboudchou dans le forum Autres outils décisionnels
    Réponses: 4
    Dernier message: 02/01/2007, 14h25
  3. Votre EDI préferé pour Java (2003-2004) ?
    Par christopheJ dans le forum EDI et Outils pour Java
    Réponses: 73
    Dernier message: 17/10/2005, 17h05
  4. Réponses: 4
    Dernier message: 16/10/2005, 18h30
  5. Profiler pour Java
    Par donde dans le forum Tests et Performance
    Réponses: 1
    Dernier message: 10/02/2003, 17h36

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