2014-05-01 4 views
2

Je sais que le modificateur private-package (par défaut) est censé cacher une méthode (ou un membre) pour chaque classe, à l'exception de ceux du même paquet. Cependant, j'ai découvert quelques problèmes avec ce niveau d'accès.Comportement incohérent du niveau d'accès privé du paquet

Consultez le code suivant:

// pack1/MyBaseClass.java 
package pack1; 

public class MyBaseClass { 
    /* package private */ void someMethod() { 
     System.out.println("MyBaseClass.someMethod"); 
    } 
} 


// pack1/MyDerivedClassFromOtherPackage.java 
package pack1; 

import pack2.MyDerivedClassInAnotherPackage; 

public class MyDerivedClassFromOtherPackage extends MyDerivedClassInAnotherPackage { 
    @Override 
    /* package private */ void someMethod() { 
     System.out.println("MyDerivedClassFromOtherPackage.someMethod"); 
     // super.someMethod(); // can't compile 
    } 
} 


//pack2/MyDerivedClassInAnotherPackage.java 
package pack2; 

import pack1.MyBaseClass; 

public class MyDerivedClassInAnotherPackage extends MyBaseClass { 
    // @Override // can't do this (compile error) 
    /* package private */ void someMethod() { 
     System.out.println("MyDerivedClassInAnotherPackage.someMethod"); 
    } 
} 

Donc, fondamentalement, il y a une classe de base dans le paquet pack1 avec une méthode de package-privé (MyBaseClass). Une autre classe dans pack2 (MyDerivedClassInAnotherPackage) étend MyBaseClass, et elle ne peut pas remplacer la méthode package-private (pour l'instant ok: les méthodes package-private sont accessibles uniquement dans le même package). Toutefois, une autre classe dans pack1 étend pack2.MyDerivedClassInAnotherPackage, et cette fois il peut remplacer sa méthode package-private (mais il ne peut pas appeler super.someMethod()).

Une autre chose étrange est que someMethod se comporte polymorphically pour pack1.MyDerivedClassFromOtherPackage mais pas pack2.MyDerivedClassInAnotherPackage. Le code ci-dessous devrait préciser ce que je veux dire:

package pack1; 

import pack2.MyDerivedClassInAnotherPackage; 

public class MainClass { 

    public static void main(String[] args) { 
     MyBaseClass bc = new MyBaseClass(); 
     bc.someMethod(); 
     System.out.println("-------------------------------------------------"); 

     MyBaseClass otherpack = new MyDerivedClassInAnotherPackage(); 
     otherpack.someMethod(); 
     System.out.println("-------------------------------------------------"); 

     MyBaseClass samepack = new MyDerivedClassFromOtherPackage(); 
     samepack.someMethod(); 
     System.out.println("-------------------------------------------------"); 

    } 

} 

Sortie:

MyBaseClass.someMethod 
------------------------------------------------- 
MyBaseClass.someMethod 
------------------------------------------------- 
MyDerivedClassFromOtherPackage.someMethod 
------------------------------------------------- 

Questions relatives à ces comportements:

1. How come that pack1.MyDerivedClassFromOtherPackage is allowed to override the (package-private) method of pack2.MyDerivedClassInAnotherPackage? 
2. In spite of this, why is it not possible to call super.someMethod() from pack1.MyDerivedClassFromOtherPackage? 
3. Why is the class in the same package (pack1) behaving polymorphically and the one in the other package (pack2) not? 

PS1 .: Je sais que je devrais poster un question à la fois sur SO, mais je pense que les trois questions doivent d'une manière ou d'une autre avoir la même cause. (Je soupçonne que, en réalité, pack1.MyDerivedClassFromOtherPackage.someFunction est prépondérant pack1.MyBaseClass.someFunction et non pack2.MyDerivedClassInAnotherPackage.someFunction. Mais ce ne serait toujours pas expliquer la deuxième question, et d'ailleurs je ne pouvais pas le confirmer.)

PS2 .: Je n'ai pas vraiment d'utilisation pour ce scénario. Je joue juste avec les cas de coin (en préparation pour l'examen OCA).

+0

Avez-vous essayé de remplacer someMethod dans pack2.MyDerivedClassInAnotherPackage avec le modificateur 'public'? – broncoAbierto

+0

@broncoAbierto: Je ne comprends pas votre suggestion. Si je le faisais, comment cela m'aiderait-il à comprendre le comportement du niveau d'accès paquet-privé (par défaut). (Quel est le but de la question.) – Attilio

+0

Ma conjecture est que vous ne pouvez pas remplacer car en déclarant sa visibilité à pack2-package privé, vous restreignez son accessibilité. – broncoAbierto

Répondre

0

1) Ce que vous remplacez ici n'est pas MyDerivedClassInAnotherPackage # someMethod, mais MyBaseClass # someMethod(). Le premier est ignoré en raison de la confidentialité du package, et le compilateur résout correctement le niveau remplacé à MyBaseClass, puisque votre classe enfant est dans le même package que lui.

Notez que cela sous-entend que nous supprimons l'annotation @Override de la deuxième classe dans la hiérarchie - sinon votre code ne compile même pas.

La question de suivi intéressante ici serait pourquoi le système d'annotation jette toujours une erreur alors que le code compile bien dans ce cas.

2) Parce que les super-résolutions à la superclasse immédiate, dont vous n'avez pas accès dans ce cas.

3) Editer: comme indiqué dans la réponse de BroncoAbiertos, c'est simplement parce que c'est le seul endroit où la méthode est effectivement surchargée. En fait, vous ne pouvez obtenir cette compilation qu'en supprimant l'annotation @Override de la deuxième classe comme indiqué dans la réponse 1 ci-dessus, sinon votre code ne compilera pas.

+1

En ce qui concerne la première réponse, je pense qu'elle compile parce qu'elle ne remplace pas simplement la méthode parente. Cependant, si vous ajoutez l'annotation de substitution, vous demandez au compilateur de s'assurer que vous avez écrasé quelque chose, ce qui explique pourquoi il ne compile pas. – broncoAbierto

+0

C'est vrai, mais je pensais à l'annotation dans la troisième classe de la hiérarchie. Si vous laissez cette annotation seulement, et supprimez la deuxième, le code compile, mais le processeur d'annotation se plaindra TOUJOURS d'une erreur. – csvan

+0

Merci à vous deux pour la clarification. Les deux réponses sont correctes à mon avis, mais malheureusement je ne peux en accepter qu'une ... – Attilio

0
  1. Vous ne pouvez pas surcharger someMethod dans pack2.MyDerivedClassInAnotherPackage car vous déclarez le paquet privé à pack2. C'est-à-dire que vous éliminez l'accès de pack1, limitant ainsi sa visibilité, ce qui est illégal lors du remplacement d'une méthode. Lorsque vous le remplacez à partir de pack1.MyDerivedClassFromOtherPackage la visibilité reste la même, ce qui est légal.
  2. Vous ne pouvez pas appeler super.someMethod() car vous essayez d'accéder à pack2.MyDerivedClassInAnotherPackage.someMethod(), mais vous ne pouvez pas accéder aux méthodes pack2.MyDerivedClassInAnotherPackage de pack1.
  3. Eh bien, la méthode n'est remplacée que dans pack1.MyDerivedClassFromOtherPackage, donc ce n'est pas étrange.
Questions connexes