Question En Java, différence entre paquet privé, public, protégé et privé


En Java, existe-t-il des règles claires sur le moment d'utiliser chacun des modificateurs d'accès, à savoir le défaut (paquet privé), public, protected et private, en faisant class et interface et traitant de l'héritage?


2490
2017-10-18 19:53


origine


Réponses:


Le tutoriel officiel peut vous être utile.

            │ Classe │ Paquet │ Sous-classe │ Sous-classe │ Monde
            │ │ │ (même paquet) │ (diff pkg) │
────────────────────────────────────────────────────────────────────────────────── ──┼────────
public │ + │ + │ + │ + │ +
────────────────────────────────────────────────────────────────────────────────── ──┼────────
protégé │ + │ + │ + │ + │
────────────────────────────────────────────────────────────────────────────────── ──┼────────
pas de modificateur │ + │ + │ + │ │
────────────────────────────────────────────────────────────────────────────────── ──┼────────
privé │ + │ │ │ │

+: accessible
blank: pas accessible

4645
2017-10-18 19:57



(Attention: je ne suis pas un programmeur Java, je suis un programmeur Perl, Perl n'a pas de protections formelles, c'est peut-être pourquoi je comprends si bien le problème :))

Privé

Comme on pourrait le penser, seul le classe dans lequel il est déclaré peut le voir.

Forfait Privé

Peut seulement être vu et utilisé par le paquet dans lequel il a été déclaré. C'est la valeur par défaut de Java (que certains considèrent comme une erreur).

Protégé

Package Private + peut être vu par les sous-classes ou les membres du package.

Publique

Tout le monde peut le voir.

Publié

Visible en dehors du code que je contrôle. (Bien que ce ne soit pas la syntaxe Java, c'est important pour cette discussion).

C ++ définit un niveau supplémentaire appelé "ami" et moins vous en saurez, mieux ce sera.

Quand devriez-vous utiliser quoi? L'idée est l'encapsulation pour cacher l'information. Autant que possible, vous voulez cacher le détail de la façon dont quelque chose est fait de vos utilisateurs. Pourquoi? Parce que vous pouvez ensuite les changer plus tard et ne pas casser le code de n'importe qui. Cela vous permet d'optimiser, de refactoriser, de reconcevoir et de corriger les bugs sans craindre que quelqu'un utilise ce code que vous venez de réviser.

Donc, la règle générale est de rendre les choses aussi visibles qu'elles doivent l'être. Commencez avec privé et ajoutez seulement plus de visibilité au besoin. Rendre public seulement ce qui est absolument nécessaire à l'utilisateur de savoir, chaque détail que vous faites des crampes publiques votre capacité à repenser le système.

Si vous souhaitez que les utilisateurs puissent personnaliser les comportements, plutôt que de rendre les internals publics afin de pouvoir les remplacer, il est souvent préférable de les insérer dans un objet et de rendre cette interface publique. De cette façon, ils peuvent simplement brancher un nouvel objet. Par exemple, si vous écriviez un lecteur de CD et que vous vouliez que l'option "go find info sur ce CD" soit personnalisable, plutôt que de rendre ces méthodes publiques, vous mettriez toute cette fonctionnalité dans son propre objet et rendriez seulement votre objet public getter / setter . De cette façon, être avare d'exposer ses tripes encourage une bonne composition et une séparation des préoccupations

Personnellement, je reste avec "privé" et "public". Beaucoup de langues OO ont juste cela. "Protected" peut être utile, mais c'est vraiment une triche. Une fois qu'une interface est plus que privée, c'est hors de votre contrôle et vous devez aller chercher dans le code d'autres personnes pour trouver des utilisations.

C'est là qu'intervient l'idée de "publié". Changer une interface (la refactoriser) nécessite que vous trouviez tout le code qui l'utilise et que vous le changiez aussi. Si l'interface est privée, eh bien pas de problème. Si c'est protégé, vous devez aller chercher toutes vos sous-classes. Si c'est public, vous devez aller chercher tout le code qui utilise votre code. Parfois, cela est possible, par exemple si vous travaillez sur du code d'entreprise à usage interne, cela n'a pas d'importance si une interface est publique. Vous pouvez récupérer tout le code du référentiel d'entreprise. Mais si une interface est "publiée", s'il y a du code qui l'utilise hors de votre contrôle, alors vous êtes arrosé. Vous devez supporter cette interface ou risquer de casser le code. Même les interfaces protégées peuvent être considérées comme publiées (c'est pourquoi je ne me soucie pas de protéger).

De nombreuses langues trouvent que la nature hiérarchique du public / protégé / privé est trop limitative et ne correspond pas à la réalité. À cette fin, il y a le concept d'un classe de traits, mais c'est un autre spectacle.


357
2017-10-18 21:17



Voici une meilleure version de la table. (Preuve du futur avec une colonne pour les modules.)

Java Access Modifiers

Explications

  • UNE privé le membre est seulement accessible dans la même classe que celle déclarée.

  • Un membre avec pas de modificateur d'accès est uniquement accessible dans les classes du même package.

  • UNE protégé le membre est accessible dans toutes les classes dans le même paquet et dans des sous-classes d'autres paquets.

  • UNE Publique membre est accessible à toutes les classes (sauf si elle réside dans un module cela n'exporte pas le paquet dans lequel il est déclaré).


Quel modificateur choisir?

Access modiers est un outil pour vous aider à prévenir accidentellement l'encapsulation(*). Demandez-vous si vous avez l'intention que le membre soit interne à la classe, au paquet, à la hiérarchie des classes ou pas du tout interne, et choisissez le niveau d'accès en conséquence.

Exemples:

  • Un champ long internalCounter devrait probablement être privé puisque c'est mutable et un détail de mise en œuvre.
  • Une classe qui ne devrait être instanciée que dans une classe de fabrique (dans le même paquet) devrait avoir un constructeur restreint de paquet, puisqu'il ne devrait pas être possible de l'appeler directement depuis l'extérieur du paquet.
  • Un interne void beforeRender() La méthode appelée juste avant le rendu et utilisée comme crochet dans les sous-classes doit être protégée.
  • UNE void saveGame(File dst) La méthode appelée à partir du code GUI doit être publique.

(*) Qu'est-ce que l'encapsulation exactement?


243
2017-11-10 10:27



                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |    
Modifier of x \ |               |           |               |       
————————————————*———————————————+———————————+———————————————+———————
public          |              |          |              |      
————————————————+———————————————+———————————+———————————————+———————
protected       |              |          |              |   ✘   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |              |          |       ✘       |   ✘   
————————————————+———————————————+———————————+———————————————+———————
private         |              |     ✘     |       ✘       |   ✘    

165
2018-01-09 21:42



Règle facile. Commencez par déclarer tout privé. Et puis progresser vers le public lorsque les besoins se présentent et que le design le justifie.

Lorsque vous présentez des membres, demandez-vous si vous présentez des choix de représentation ou des choix d'abstraction. Le premier est quelque chose que vous voulez éviter car il introduira trop de dépendances sur la représentation réelle plutôt que sur son comportement observable.

En règle générale, j'essaye d'éviter de surcharger les implémentations de méthodes par sous-classe; c'est trop facile de bousiller la logique. Déclarez les méthodes protégées abstraites si vous avez l'intention de les surcharger.

En outre, utilisez l'annotation @Override lors de la substitution pour empêcher les choses de se casser lorsque vous refactorisez.


130
2017-10-18 20:00



C'est en fait un peu plus compliqué qu'une simple grille. La grille vous indique si un accès est autorisé, mais qu'est-ce qui constitue exactement un accès? En outre, les niveaux d'accès interagissent avec les classes imbriquées et l'héritage de manière complexe.

L'accès "par défaut" (spécifié par l'absence d'un mot-clé) est aussi appelé paquet-privé. Exception: dans une interface, aucun modificateur ne signifie un accès public; les modificateurs autres que publics sont interdits. Les constantes enum sont toujours publiques.

Résumé

Un accès à un membre avec ce spécificateur d'accès est-il autorisé?

  • Le membre est private: Uniquement si le membre est défini dans la même classe que le code appelant.
  • Le membre est privé du paquet: seulement si le code appelant est dans le paquet qui l'entoure immédiatement.
  • Le membre est protected: Même package ou si le membre est défini dans une superclasse de la classe contenant le code appelant.
  • Le membre est public: Oui.

Quels spécificateurs d'accès s'appliquent à

Les variables locales et les paramètres formels ne peuvent pas prendre de spécificateurs d'accès. Comme ils sont intrinsèquement inaccessibles à l'extérieur selon les règles de délimitation, ils sont effectivement privés.

Pour les classes du premier niveau, uniquement public et package-private sont autorisés. Ce choix de conception est probablement dû au fait que protected et private serait redondant au niveau du paquet (il n'y a pas d'héritage des paquets).

Tous les spécificateurs d'accès sont possibles sur les membres de la classe (constructeurs, méthodes et fonctions membres statiques, classes imbriquées).

En relation: Java Class Accessibility

Commande

Les spécificateurs d'accès peuvent être strictement commandés

public> protected> package-private> privé

ce qui signifie que public fournit le plus d'accès, private le moins. Toute référence possible sur un membre privé est également valable pour un membre de package privé; toute référence à un membre de package privé est valide sur un membre protégé, et ainsi de suite. (Donner accès aux membres protégés à d'autres classes dans le même paquet a été considéré comme une erreur.)

Remarques

  • Les méthodes d'une classe sont autorisé à accéder aux membres privés d'autres objets de la même classe. Plus précisément, une méthode de classe C peut accéder à des membres privés de C sur des objets de n'importe quelle sous-classe de C. Java ne supporte pas la restriction d'accès par instance, seulement par classe. (Comparer avec Scala, qui le supporte en utilisant private[this].)
  • Vous devez accéder à un constructeur pour construire un objet. Ainsi, si tous les constructeurs sont privés, la classe ne peut être construite que par du code vivant dans la classe (typiquement des méthodes d'usine statiques ou des initialiseurs de variables statiques). De même pour les constructeurs de paquets privés ou protégés.
    • Le seul fait d'avoir des constructeurs privés signifie également que la classe ne peut pas être sous-classée en externe, puisque Java requiert les constructeurs d'une sous-classe pour appeler implicitement ou explicitement un constructeur de superclasse. (Il peut toutefois contenir une classe imbriquée qui la sous-classe.)

Cours intérieurs

Vous devez aussi considérer imbriqué portées, telles que les classes internes. Un exemple de la complexité est que les classes internes ont des membres, qui eux-mêmes peuvent prendre des modificateurs d'accès. Vous pouvez donc avoir une classe interne privée avec un membre public; Le membre peut-il être consulté? (Voir ci-dessous.) La règle générale est de regarder la portée et penser récursivement pour voir si vous pouvez accéder à chaque niveau.

Cependant, c'est assez compliqué, et pour plus de détails, consultez la spécification de langage Java. (Oui, il y a eu des bogues de compilateur dans le passé.)

Pour un avant-goût de la façon dont ceux-ci interagissent, considérons cet exemple. Il est possible de "fuir" les classes internes privées; C'est généralement un avertissement:

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

Sortie du compilateur:

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

Quelques questions connexes:


94
2017-09-13 07:38



En règle générale:

  • privé: portée de la classe.
  • défaut (ou paquet-privé): portée du package.
  • protégé: étendue du package + enfant (comme le paquet, mais nous pouvons le sous-classer à partir de différents paquets). Le modificateur protected conserve toujours la relation "parent-enfant".
  • Publique: partout.

En conséquence, si nous divisons l'accès en trois droits:

  • (Direct (invoquer d'une méthode à l'intérieur de la même classe).
  • (Référence (invoquer une méthode en utilisant une référence à la classe, ou via la syntaxe "point").
  • (Héritage (via le sous-classement).

alors nous avons ce tableau simple:

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+

63
2017-12-18 18:01



En très court

  • public: accessible de partout.
  • protected: accessible par les classes du même package et les sous-classes résidant dans un package.
  • default (pas de modificateur spécifié): accessible par les classes du même paquet.
  • private: accessible uniquement dans la même classe.

43
2017-10-27 17:49