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

avec Java Discussion :

Wildcard et compilation


Sujet :

avec Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    62
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 62
    Points : 59
    Points
    59
    Par défaut Wildcard et compilation
    Bonsoir... ou bonjour ! (il est si tard qu'en fait il est très tôt )

    Quelques questions s'agissant du type wildcard. Mais d'abord un premier bout de 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
    import java.util.ArrayList;
     
    public class TestJava2 
    {
    	private static void addObject(ArrayList<?> list)
    	{
    		list.add( new Object() ); // Erreur à la compilation (1)
    	}
     
    	private static void addInteger(ArrayList<?> list)
    	{
    		list.add( new Integer(1) ); // Erreur à la compilation (2)
    	}
     
    	public static void main(String[] args) 
        {
        	ArrayList<?> list = new ArrayList<Integer>();
        	list.add(new Integer(1)); // Erreur à la compilation (3)
        	list.add(new Object()); // Erreur à la compilation (4)
        }
    }
    Questions :

    1) Sauf erreur, dans un code utilisant les generics, le point d'interrogation '?' représente un type inconnu. De fait, je comprends que le compilateur grogne s'agissant de addObject() et addInteger() : ces méthodes ignorent le type des données stockées dans les ArrayList; elles ignorent s'il s'agit d'Objects, d'Integers, ou autre; en conséquence il est normal de refuser l'appel à la méthode add(). Confirmez-vous qu'il s'agit bien là de la raison qui amène le compilateur à rejeter ces lignes (1) et (2) ?

    2) Sauf erreur, suite à une opération de "type erasure", list est en fait un objet de type ArrayList (on a perdu l'information "<Integer>") : est-ce exact ?

    3) Il n'empêche que je reste dubitatif quant à la cause des erreurs 3 et 4... Si list est considérée comme un ArrayList, sans aucune précision quant au type des données stockés, alors la situation est similaire à celles des erreurs (1) et (2)... Toutefois, les erreurs (3) et (4) concernent des lignes de code dans le main() où est créée la variable list... en conséquence le compilateur est en mesure de savoir que list est une ArrayList<Integer>... Aussi pourquoi l'erreur (3) : il s'agit d'une situation où il n'y a pas d'incertitude sur la nature de list ?

    Autre bout de code, et deux autres questions !

    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
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.List;
     
    public class TestJava2 
    {
    	public static void main(String[] args) throws IOException
        {
    		final Path pathSource = Paths.get("d:/mon_fichier_source.txt");
    		final Path pathCible = Paths.get("d:/mon_fichier_cible.txt");
    		final List<String> lignes = Files.readAllLines(pathSource, StandardCharsets.UTF_8);
    		Files.write(pathCible, lignes, StandardCharsets.UTF_8);
    	}
    }
    Questions :

    4) Pourquoi ça compile ? On utilise la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) throws IOException
    String implémente les interfaces Serializable, CharSequence et Comparable<String>. Donc si on passe un objet de type String à write(), il est logique que le compilateur ne trouve rien à redire... Mais dans le cas présent, on passe une List<String>, et je ne vois pas comment cette liste se conforme à l'interface CharSequence ou dérivée ?


    5) A l'exécution, ça ne fonctionne pas tout à fait ! Avec le fichier ci-dessous (qui est bien en UTF-8 w/o BOM, Notepad++ est affirmatif), j'obtiens un fichier "mon_fichier_cible.txt" identique à la source n'était une ligne vide supplémentaire en fin de fichier ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    bla
    blabla
    €ïÔù
    EOF
    D'avance merci pour tout éclaircissement

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 10
    Points : 19
    Points
    19
    Par défaut
    Pour les question 3 et 4 seul la déclaration de ta variable est prise en compte et pas son initialisation. D'ailleur en java 7 le typage de l'initialisation est devenu facultatif.

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    List<Integer> list = new ArrayList<>();
    Le typage c'est quelque chose d’extrêmement simple. A la compilation le compilateur va vérifier que tous les objets (ici de ta liste) héritent bien tous de la même class, et c'est tout !

    Donc tu comprends pourquoi tu ne peux pas ajouter d'Integer ou Objet dans une liste de type inconnu.

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par Isidore.76 Voir le message
    1) Sauf erreur, dans un code utilisant les generics, le point d'interrogation '?' représente un type inconnu. De fait, je comprends que le compilateur grogne s'agissant de addObject() et addInteger() : ces méthodes ignorent le type des données stockées dans les ArrayList; elles ignorent s'il s'agit d'Objects, d'Integers, ou autre; en conséquence il est normal de refuser l'appel à la méthode add(). Confirmez-vous qu'il s'agit bien là de la raison qui amène le compilateur à rejeter ces lignes (1) et (2) ?
    Oui.

    Citation Envoyé par Isidore.76 Voir le message
    2) Sauf erreur, suite à une opération de "type erasure", list est en fait un objet de type ArrayList (on a perdu l'information "<Integer>") : est-ce exact ?
    Oui, à l'exécution. Tant que tu es encore en train de lire le code source tu as rien perdu du tout.

    Citation Envoyé par Isidore.76 Voir le message
    3) Il n'empêche que je reste dubitatif quant à la cause des erreurs 3 et 4... Si list est considérée comme un ArrayList, sans aucune précision quant au type des données stockés, alors la situation est similaire à celles des erreurs (1) et (2)... Toutefois, les erreurs (3) et (4) concernent des lignes de code dans le main() où est créée la variable list... en conséquence le compilateur est en mesure de savoir que list est une ArrayList<Integer>... Aussi pourquoi l'erreur (3) : il s'agit d'une situation où il n'y a pas d'incertitude sur la nature de list ?
    Ah, les idées bizarres qu'on peut avoir quand l'ensemble est encore un peu gros à digérer en une fois.
    Pourquoi, pourquoi, quelqu'un voudrait-il, sur cette planète, que ce cas soit différent des erreurs (1) et (2) ?

    Oui, il est du domaine du possible, pour le compilateur, de faire une analyse de flux qui lui permette de savoir que les ArrayList, au départ, viennent d'un type qui autorise ces ajouts.
    Tout comme il aurait aussi pu le faire avec les cas (1) et (2) qui sont private et appelées nulles part, donc on sait qu'il n'y a pas de contradiction dans les types. Si elles n'étaient pas private, d'autres classes pourraient les appeler et le compilateur ne pourrait rien garantir, mais là il peut... C'est juste qu'il a aucune intention de le faire, parce que ce serait l'inverse de son rôle !

    Toi, programmeur, a clairement indiqué ton intention que ces ArrayList soient de type ArrayList<?> et pas ArrayList<Integer> ou autre chose.
    Pourquoi le compilateur ignorerait-il ta volonté ? Si tu avais voulu du ArrayList<Integer>, tu aurais mis ArrayList<Integer>. Cette différence que tu as choisi de faire sciemment, fait bel et bien une différence.

    Citation Envoyé par Isidore.76 Voir le message
    4) Pourquoi ça compile ? On utilise la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static Path write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) throws IOException
    String implémente les interfaces Serializable, CharSequence et Comparable<String>. Donc si on passe un objet de type String à write(), il est logique que le compilateur ne trouve rien à redire... Mais dans le cas présent, on passe une List<String>, et je ne vois pas comment cette liste se conforme à l'interface CharSequence ou dérivée ?
    Tu as mal lu. Le paramètre est de type Iterable<? extends CharSequence>. List étend Collection qui étend Iterable. Et comme tu l'as remarqué, String implémente CharSequence. Ce qui fait que List<String> est sous-type de Iterable<? extends CharSequence>.
    Si tu lui passais une String, ça ne compilerait pas, car String n'est pas sous-type de Iterable<quoi que ce soit>.

    Citation Envoyé par Isidore.76 Voir le message
    5) A l'exécution, ça ne fonctionne pas tout à fait ! Avec le fichier ci-dessous (qui est bien en UTF-8 w/o BOM, Notepad++ est affirmatif), j'obtiens un fichier "mon_fichier_cible.txt" identique à la source n'était une ligne vide supplémentaire en fin de fichier ?
    Ce n'est pas tellement étonnant quand on raisonne en liste de lignes plutôt qu'en fichier entier, tu ne trouves pas ?
    L'usage, soyons francs, est de toujours terminer un fichier texte par une ligne vide. Cette ligne vide n'est pas intéressante, elle est vide, alors readAll() ne l'inclut pas à la liste.

    Maintenant supposons qu'on lise un fichier qui n'inclut pas de ligne vide à la fin, et se termine juste à la fin de la dernière ligne. Ce n'est pas une raison pour rejeter ce fichier, il sera juste lu exactement de la même manière que s'il faisait comme tout le monde.
    Ce qui fait qu'on n'est plus capable de faire la différence entre s'il incluait une ligne vide à la fin et s'il ne le faisait pas. Et ce n'est pas grave. Parce qu'on n'en a pas besoin.
    Si ton but est de copier des fichiers à l'identique, tu ne devrais même pas voir la moindre notion de String. Il faudrait utiliser readAllBytes().
    Enfin, il faudrait utiliser copy() bien sûr, mais je pense qu'on s'est compris.

    Edit : je me rends compte que la notion est plus claire quand on considère que "fin de ligne" est quelque chose qu'on trouve à la fin de chaque ligne, plutôt que de parler de ligne vide à la fin d'un fichier.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    62
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 62
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Oui.
    Tu as mal lu. Le paramètre est de type Iterable<? extends CharSequence>.
    Exact ! Je n'avais pas noté le Iterable, mea-culpa !


    Citation Envoyé par thelvin Voir le message
    Si ton but est de copier des fichiers à l'identique, tu ne devrais même pas voir la moindre notion de String. Il faudrait utiliser readAllBytes().
    Enfin, il faudrait utiliser copy() bien sûr, mais je pense qu'on s'est compris.
    On s'est compris A la lecture de mes différents posts (auxquels tu as la gentillesse de répondre avec d'évidentes compétences) tu auras compris que je continue de creuser java.nio, testant des bouts de code jusqu'à de petits programmes, et pour le coup j'ai été surpris de cette "ligne" supplémentaire et des +2 octets à la taille du fichier ! Plus familier avec l'univers dotnet, j'ai testé à l'instant sous cet environnement, et utilisé une classe System.IO.File aux méthodes static trèèèès semblables, pour un résultat... identique ! Et encore une fois je ne m'y attendais pas ! Comme quoi

    Merci bien !

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

Discussions similaires

  1. Réponses: 15
    Dernier message: 10/10/2002, 19h19
  2. [Installation] Borland Compiler 5.5 sous XP
    Par Ligey dans le forum Autres éditeurs
    Réponses: 16
    Dernier message: 28/09/2002, 22h45
  3. dans le fond, la compilation...
    Par deltapositive dans le forum C++Builder
    Réponses: 5
    Dernier message: 17/09/2002, 12h14
  4. Vitesse de compilation
    Par srvremi dans le forum C++Builder
    Réponses: 5
    Dernier message: 30/07/2002, 16h49
  5. Réponses: 1
    Dernier message: 27/05/2002, 01h44

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