web-dev-qa-db-fra.com

différence entre les modificateurs d'accès protégés et les paquets d'accès privés en Java?

J'ai vu divers articles sur les différences entre les modificateurs privés protégés et les modificateurs privés. Une chose que j'ai trouvée contradictoire entre ces deux posts

  1. Est-ce que l'accès membre "package private" n'est pas synonyme d'accès par défaut (sans modificateur)?

    En cela, la réponse acceptée dit que

    Le modificateur protected spécifie que le membre n'est accessible que par son propre package (comme avec package-private) et, en outre, par une sous-classe de sa classe dans un autre package.

  2. Pourquoi le modificateur protected se comporte différemment ici dans la sous-classe Java?

    En cela, la réponse acceptée dit que

    Pour satisfaire un accès de niveau protégé, deux conditions doivent être remplies:

    • Les classes doivent être dans le même package.
    • Il doit y avoir une relation d'héritage.

Ne sont-ils pas contradictoires? d'après ce que j'ai compris d'autres articles, le premier message donne la réponse correcte qui protège == package-private + subclass dans un autre package. 

Si cette instruction est correcte, alors pourquoi ce code échoue-t-il avec le message d'erreur suivant sur ma sous-classe Cat à la ligne 17

The method testInstanceMethod() from the type Animal is not visible 

mon code pour super et sous-classe sont ci-dessous.

package inheritance;

public class Animal {

    public static void testClassMethod() {
        System.out.println("The class" + " method in Animal.");
    }
    protected void testInstanceMethod() {
        System.out.println("The instance " + " method in Animal.");
    }
}

package testpackage;

import inheritance.Animal;

public class Cat extends Animal{
        public static void testClassMethod() {
            System.out.println("The class method" + " in Cat.");
        }
        public void testInstanceMethod() {
            System.out.println("The instance method" + " in Cat.");
        }

        public static void main(String[] args) {
            Cat myCat = new Cat();
            Animal myAnimal = myCat;
            myAnimal.testClassMethod();
            myAnimal.testInstanceMethod();
        }
    }

Veuillez expliquer pourquoi le code ci-dessus a échoué. Cela serait très utile. Merci

28
eagertoLearn

La première réponse est fondamentalement correcte - les membres de protected sont accessibles via

  • classes du même paquet
  • sous-classes de la classe déclarante à partir d'autres packages

Cependant, il y a un petit truc: 

6.6.2 Détails sur l'accès protégé

Un membre protégé ou un constructeur d'objet peut être accédé de l'extérieur du package dans lequel il est déclaré uniquement par le code responsable de la mise en œuvre de cet objet.

Cela signifie que les sous-classes d'autres packages ne peuvent pas accéder aux membres protected des instances arbitraires de leurs superclasses, ils ne peuvent y accéder que par les instances de leur propre type (où type est un type d'expression à la compilation, puisqu'il s'agit d'une vérification à la compilation).

Par exemple (en supposant que ce code est dans Cat):

Dog dog = new Dog();
Animal cat = new Cat();

dog.testInstanceMethod(); // Not allowed, because Cat should not be able to access protected members of Dog
cat.testInstanceMethod(); // Not allowed, because compiler doesn't know that runtime type of cat is Cat

((Cat) cat).testInstanceMethod(); // Allowed

Cela a du sens, car accéder aux membres protected de Dog par Cat peut détruire les invariants de Dog, alors que Cat peut accéder à ses propres membres protected en toute sécurité, car il sait comment assurer ses propres invariants.

Règles détaillées:

6.6.2.1 Accès à un membre protégé

Soit C la classe dans laquelle un membre protégé m est déclaré. L'accès n'est autorisé que dans le corps d'une sous-classe S de C. De plus, si Id désigne un champ d'instance ou une méthode d'instance, alors:

  • Si l'accès se fait par un nom qualifié Q.Id, où Q est un ExpressionName, l'accès est autorisé si et seulement si le type de l'expression Q est S ou une sous-classe de S.
  • Si l'accès se fait par une expression d'accès au champ E.Id, où E est une expression primaire ou par une expression d'appel de méthode E.Id (...), Où E est une expression primaire, l'accès est autorisé si et seulement si le type de E est S ou une sous-classe de S.

6.6.2.2 Accès qualifié à un constructeur protégé

Soit C la classe dans laquelle un constructeur protégé est déclaré et S est la classe la plus interne dans la déclaration de laquelle se produit l'utilisation du constructeur protégé. Ensuite:

  • Si l'accès se fait par une invocation de constructeur de superclasse super (...) Ou par un appel de constructeur de superclasse qualifié de la forme E.super (...), Où E est une expression primaire, l'accès est autorisé.
  • Si l'accès se fait par une expression de création d'instance de classe anonyme de la forme nouveau C (...) {...} ou par une expression de création d'instance de classe qualifiée de forme E.new C (...) {... }, où E est une expression primaire, l'accès est autorisé.
  • Sinon, si l'accès se fait par une expression de création d'instance de classe simple de la forme nouvelle C (...) Ou par une expression de création d'instance de classe qualifiée de forme E.new C (...), Où E est une expression primaire , alors l'accès n'est pas autorisé. Une expression de création d'instance de classe (qui ne déclare pas de classe anonyme) ne peut accéder à un constructeur protégé qu'à partir du package dans lequel elle est définie.

Voir également:

24
axtavt

En accès protégé, les membres sont accessibles dans le même package et les membres de classe hérités d'un autre package sont également accessibles.

Dans l'accès aux packages, les membres des classes d'un même package sont accessibles. Les membres de classe dans d'autres packages ne sont pas accessibles via l'accès aux packages.

2
Muhammad kazmi

Vous avez créé une instance Cat et l'avez convertie en son type de classe supérieure, à savoir le type Animal. Selon le type d’animal, sa méthode testInstance est visible dans le même package ou dans n’importe quel sous-type. Si vous n'avez pas transtypé en type Animal, le code sera compilé.

J'espère que cela pourra aider 

./Arun

0
Arun