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 :

Demande d'une explication


Sujet :

avec Java

  1. #1
    Membre du Club
    Homme Profil pro
    12
    Inscrit en
    Mai 2014
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : 12
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 67
    Points : 61
    Points
    61
    Par défaut Demande d'une explication
    Bonsoir à tous, j'espère que vous allez bien !

    je me prépare pour un examen en java et je n'ai malheureusement pas compris un truc, et c'est pour cette raison que je vous écris cette question à fin de trouver un explication.

    ma question est la suivante :

    Considérons cet exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    class A
    { public void f (int n) { ..... }
    }
    class B extends A
    { private void f (int n) { ..... } // tentative de redéfinition de f de A
    }
    Il est rejeté par le compilateur, tandis que celle ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class A
    { private void f (int n) { ..... }
    }
    class B extends A
    { public void f (int n) { ..... } // redéfinition de f avec extension
    }

    le livre dont j'ai trouvé cet exemple explique ceci par le fait que : la redéfinition d’une méthode ne doit pas diminuer les droits d’accès à cette méthode.


    qui peut m'expliquer la différence entre les deux ?

  2. #2
    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
    Dans le premier cas, tu as une méthode f dans A publique, dans B tu la redéfini et tu la rends privée. Le language interdit cela, tout simplement car on aurait un problème avec ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    B b = new B();
    A a = b; 
    b.f(1); // erreur f est privé
    a.f(1); // mais ceci marcherait car A.f est déclaré public
    Bref par propreté le language a choisi de l'interdire.



    Dans ton deuxième cas, c'est différent. D'abord f est privé et tu le fait passer à public. On peux rendre une méthode plus accessible qu'elle ne l'était dans le parent. On peux la faire passer de protected a public par exemple. Mais ce n'est de toutes façons pas ce que l'on fait ici. A.f est privé, et une méthode privée, ça ne se redéfini pas car ce n'est pas hérité. Donc B ne connait pas A.f et a tout le loisir de définir f comme il le désire. Aucune restriction car f n'existe pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    B b = new B();
    A a = b; 
    b.f(1); // ok, f est public
    a.f(1); // a n'a pas de méthode f accessible.

  3. #3
    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
    C'est plus que par "propreté" que c'est interdit, c'est une des bases de la conception orientée objet : on ne peut pas réduire la visibilité des méthodes/propriétés d'une classe dans les classes filles (Mots clés : héritage, polymorphisme).

    Ce n'est pas possible pour une seule raison : tout ce qui est visible en haut de la pyramide d'héritage est toujours visible plus bas.

    Exemple :
    Tu crées une classe qu'on va appeler Toto !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public class Toto{
         private String toString(){
              return "can't touch this";
         }
    }
    Imaginons que ça compile... (imaginons... ce n'est pas le cas...)

    Toto est un Object par défaut (toutes les classes héritent à minima de Object)
    Du coup, imaginons le fragment de code ci dessous

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Toto myToto = new Toto();
    //myToto.toString(); // ici, le code ne pourrait pas compiler parce que toString est privé
    Object sameToto = myToto; //totalement légal, Toto est un Object
    sameToto.toString(); // ici, ça compile parce que la méthode toString est visible dans Object... Mais pas dans Toto... Or sameToto est un Toto...
    Du coup, comment on fait pour être sur que ta méthode privée ne peut pas être appelée ? Tu ne peux pas vu qu'il suffirait d'utiliser une classe supérieure dans la hiérarchie.


    Tu descends toujours depuis un objet le plus générique possible (Object) vers des objets dans la hérarchie de classe qui sont de plus en plus typés
    Object --> EtreVivant --> Vertebre --> Mammifere --> Canide --> ChienDomestique --> Tequel --> TequelNain
    Chaque étape rajoute des précisions sur le type d'objet manipulé. Du coup, tu sais qu'un TequelNain aura les propriétés inhérente à un Mammifere
    Je ne suis pas mort, j'ai du travail !

  4. #4
    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 eulbobo Voir le message
    C'est plus que par "propreté" que c'est interdit,
    Le côté "propre" vient surtout avec le fait que c'est le cas particulier private. L'accès private décrit des choses qui ne concernent que la classe en cours, et donc, il en ressort que pour les autres classes, ce qui est private n'existe pas.
    Avec private il n'y a donc pas de redéfinition. Et sans redéfinition, pas de diminution ou d'augmentation de droit. Une méthode private n'a aucun rapport avec aucune autre méthode où qu'elle soit.

    Et donc s'il n'y a pas de redéfinition ou de diminution de droit, on peut dans ce cas se demander pourquoi on a pas le droit, dans une classe descendante, de créer une nouvelle méthode, dont il se trouve par hasard qu'elle a la même signature qu'une méthode héritée.
    Réponse : par propreté. Pour éviter des confusions et erreurs stupides.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  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
    Citation Envoyé par thelvin Voir le message
    Avec private il n'y a donc pas de redéfinition.
    A partir du moment où il y a une signature de méthode "visible" par une classe fille, toute méthode ayant la même signature est par définition une surcharge. Dans le cas contraire, ça voudrait dire que tu pourrais avoir deux méthodes dans la même classe qui ne diffèrent que par leur modificateur de visibilité (ce qui voudrait dire que le modificateur de visibilité ferait partie de la signature de la méthode).

    On est donc bien sur une limitation de conception, et pas d'un élément pour rendre les choses plus propres... Sinon, tout masquage de nom serait interdit (comme par exemple créer une méthode qui a un nom de constructeur).
    Je ne suis pas mort, j'ai du travail !

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Il n'y a jamais redéfinition d'une méthode private :

    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
    37
    38
    39
    40
    41
    42
    public class A {
     
    	public String getNom() {
    		return getClass().getSimpleName();
    	}
     
    	public void bidule() {
    		prefix("bidule");
    		truc();
    	}
     
    	protected void prefix(String nomMethod) {
    		System.out.print(getNom()+"."+nomMethod+"(): ");
    	}
     
    	private void truc() {
    		System.out.println("Je suis A");
    	}
     
    	public static class B extends A {
     
    		private void truc() {
    			System.out.print("Je suis B mais... ");
    			super.truc();
    		}
     
    		public void machin() {
    			prefix("machin");
    			truc();
    		}
     
    	}
     
    	public static void main(String[] args) {
    		new A().bidule();
    		new B().bidule();
    		new B().machin();
    		new C().bidule();
    		new C().machin();
    	}
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class C extends A {
     
    	private void truc() {
    		System.out.println("Je suis C");
    	}
     
    	public void machin() {
    		prefix("machin");
    		truc();
    	}
     
    }
    L'exécution affiche :
    A.bidule(): Je suis A
    B.bidule(): Je suis A
    B.machin(): Je suis B mais... Je suis A
    C.bidule(): Je suis A
    C.machin(): Je suis C
    
    Si truc() de C rédéfinissait truc() de A, alors C.bidule() devrait afficher "Je suis C". Mais c'est bien truc() de A qui est appelé. Par contre, dans B, la visibilité de la méthode private de A rend bien possible son appel, mais pas sa redéfinition.

    Par contre, je ne comprend pas l'histoire de l'interdiction, par propreté ou pas : j'ai bien créé une méthode truc() private dans C qui fait son "truc", alors que celle de A continue de faire le sien (appelée par bidule(), elle continue d'afficher "Je suis A")
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    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
    Comme ce que je disais : il y a surcharge à partir du moment où il y a visibilité depuis une classe fille.
    Si toutes tes méthodes "truc" sont private, elles ne sont jamais visibles par personne (exception faite de l'inner class qui peut voir toutes les propriétés et méthodes de la classe qui la contient, mais les inner class ont des relations "privilégiées" avec leur conteneur)

    Du moment qu'une méthode est visible à un niveau, c'est qu'il est nécessaire que toute la hiérarchie descendante puisse la voir à minima de la même manière !
    Je ne suis pas mort, j'ai du travail !

  8. #8
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    truc() de B ne redéfinit pas truc() de A, malgré que truc() de A soit visible dans B (et, donc, appelable). Les 2 méthodes ont le même nom, la même signature, mais sont 2 méthodes différentes, chacune dans leur propre classe. private définit la portée (ou visibilité) de la méthode : elle n'est visible(= appelable) que dans la classe elle-même, mais n'existe bien que la classe qui la déclare.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  9. #9
    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 eulbobo Voir le message
    Ce n'est pas possible pour une seule raison : tout ce qui est visible en haut de la pyramide d'héritage est toujours visible plus bas.
    Ca reste un choix du langage, on aurait pu constuire le langage avec d'autres règles cohérentes permettant de réduire la visibilité. Ainsi pour reprendre ton exemple toto, on aurait pu tout aussi bien s'assurer que le private n'est pas accessible en construisant le langage avec la règle: sameToto.toString() appelle la première méthode toString accessible dans la chaine d'héritage. Du coup ca aurait appelé le toString de Object dans ce cas, celui de Toto étant inaccessible. Ca aurait pu se tenir, mais ca aurait été pas propre De la même manière on aurait pu définir le langage en déclarant qu'une méthode privée n'intervenant pas dans l'héritage, elle n'est juste pas considérée par invokevirtual et fait partie d'un jeu de quilles séparé de celui des méthodes héritées. Ca aurait cependant eu la curiosité que d'appeler toto.toString() dans un main présent dans toto aurait eu un comportement différent de toto.toString() appelé depuis un main extérieur

Discussions similaires

  1. Réponses: 11
    Dernier message: 10/04/2009, 20h51
  2. demande d'une fonction php
    Par carmen256 dans le forum Langage
    Réponses: 5
    Dernier message: 20/01/2006, 19h52
  3. Réponses: 28
    Dernier message: 18/08/2003, 11h54

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