Salut,
Envoyé par
Jrecursif
les modificateurs d'accès membre, peuvent être public, privé, protégé, ou non spécifié.
Quand c'est "non spécifié", en fait le scope est dit "package" : toutes les classes du package peuvent avoir accès à l'attribut. Attention, pas les classes de sous-packages (parce qu'un sous-package ce n'est pas le même package).
Envoyé par
Jrecursif
Ce que je sais et qui est évident c'est qu'un code
c'est d'accès privé
[...]
Ma question maintenant est la suivante. Quelles sont les règles de fonctionnement lorsqu'on appelle un membre via
ca ne répond pas du tout aux même règles et ce n'est pas documenté ni dans les tutorial java oracle, ni dans la javadoc (ou vraiment très brièvement)
Il ne faut pas le considérer de ces points de vue, mais du point de vue du compilateur et de ce qu'il considère comme classe, instance et portée, et propriétaire de la variable. Et l'accès est bien le même dans les "deux" cas (ce sont les mêmes règles qui sont appliquées).
Premièrement, il faut considérer l'accès via l'instance dans une portée donnée de classe et le type de la variable qui référence l'instance.
1 2 3 4 5 6 7 8
|
package machin;
public class Exemple {
public int publicVar;
protected int protectedVar;
private int privateVar;
int packageVar;
} |
Donc on va considérer une instance :
Exemple exemple = new Exemple();
Et l'accès, par exemple : exemple.privateVar ou exemple.publicVar... Dans le code de la classe elle-même, la variable qui référence l'instance courante, c'est this. Donc quand tu parles de System.out.println(i) tu parles de System.out.println(this.i), et donc les mêmes règles s'applique pour i dans avec this.i ou var.i, ou exemple.i, etc, par rapport au type de i, la portée déclarée de i, la classe et le package, de l'instance qui possède i, ou de celle qui possède la méthode qui accède à i.
Lorsque tu parles de System.out.println(privateVar), ce n'est possible que dans une méthode qui à une visibilité directe sur l'attribut :
- Dans une méthode de la classe (ou bloc), y compris les méthodes statiques
- Dans une classe locale d'une méthode de la classe, anonyme ou pas
- Dans une classe interne de la classe
Et ce pour n'importe quelle instance de cette classe (regarde dans l'exemple suivant la méthode methodeAvecAutreInstance), tant que c'est dit explicitement au compilateur.
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 43 44 45 46 47 48 49 50 51 52 53
| public class Exemple {
public int publicVar;
protected int protectedVar;
private int privateVar;
int packageVar;
public Exemple(int valeur) {
privateVar=valeur;
protectedVar=valeur;
publicVar=valeur;
packageVar=valeur;
}
public void methode() {
System.out.println(privateVar);
}
public void methodeAvecClasseLocale() {
class ClasseLocale {
public void methodeClassLocale() {
System.out.println(privateVar);
}
}
new ClasseLocale().methodeClassLocale();
}
public void methodeAvecClasseInterne() {
new ClasseInterne().methodeClassInterne();
}
public void methodeAvecAutreInstance(Exemple autreInstance) {
System.out.println(autreInstance.privateVar);
}
private class ClasseInterne {
public void methodeClassInterne() {
System.out.println(privateVar);
}
}
public static void main(String[] args) {
Exemple exemple = new Exemple(42);
exemple.methode();
exemple.methodeAvecClasseLocale();
exemple.methodeAvecClasseInterne();
Exemple exemple2 = new Exemple(22);
exemple.methodeAvecAutreInstance(exemple2);
// et ça fonctionne aussi ici, puisqu'on est dans une méthode de la classe (static, mais bien de la classe)
System.out.println(exemple.privateVar);
}
} |
(ce code affiche bien :
)
Simplement aucune autre instance d'autres classes que dans les cas précédents ne pourra faire cet accès.
Pour préciser "tant que c'est dit explicitement au compilateur.", on pourrait écrire :
1 2 3
| public void methodeAvecAutreInstanceDuneClasseQuiEtendCetteClasse(ExempleFille autreInstance) {
System.out.println(((Exemple)autreInstance).privateVar);
} |
Si ExempleFille extends Exemple, et ce quelque soit le package de ExempleFille.
Pour protected, il s'agit de toutes les instances de classes du package et l'instance elle-même si elle hérite (extends) de la classe, un peu comme si elle était private à cette classe. Mais pas des autres instances de la classe si elle ne fait pas partie du package.
Pour public, c'est toutes les instances de n'importe quelle classe.
Pour package, c'est toutes les instances de classe du package, comme protected mais sans la partie par héritage.
Lors de l'héritage, l'accessibilité n'est pas "transmise". Ainsi, quand une classe Fille hérite de Maman qui a une variable private i, elle n'est pas accessible d'instances de Fille, et donc encore moins de l'extérieur (d'une autre classe). C'est pourquoi, les deux dernière lignes ne compilent pas dans :
1 2 3 4 5 6
|
public void testHeritage(Maman m, Fille f, Cousin c){
System.out.println(" "+m.i+m.j+m.k);
System.out.println(" "+f.i+f.j+f.k); // f.i ne compile pas
System.out.println(" "+c.i+c.j+c.k); //c.i ne compile pas
} |
L'instance de Maman ne peut pas accéder à la variable i de f ou i de c.
Dans Fille,
1 2 3 4 5 6
|
public void testHeritage(Maman m, Fille f, Cousin c){
System.out.println(" "+m.i+m.j+m.k); // m.i ne compile pas
System.out.println(" "+f.i+f.j+f.k); // f.i ne compile pas pourquoi? on est a l'intérieur de fille !
System.out.println(" "+c.i+c.j+c.k); // c.i ne compile pas. Pourquoi c.j compile? fille n'est pas une sous classe de cousin!
} |
i est private donc inacessible par une instance de Fille, qui n'est pas Maman
i n'est pas accessible d'une instance de Fille, que ça soit sa variable, ou celle d'une autre instance de Fille. Seule une instance de Maman le peut.
pas plus i de c.
En revanche j étant protected, elle est accessible par toutes instances de classe du package de la classe qui la déclare, même si la classe par laquelle on y accède (possible parce qu'elle étend la classe, comme Fille ou Cousin) fait partie d'un autre package (comme Cousin). Donc accessible par une instance de Fille. Et d'ailleurs par n'importe quelle instance de classe du package de Maman, qu'elle hérite ou non de Maman.
Dans Cousin,
1 2 3 4 5 6 7
|
public void testHeritage(Maman m, Fille f, Cousin c){
System.out.println(" "+m.i+m.j+m.k); //m.i ne compile pas ni m.j, pourquoi m.j ne compile pas?
System.out.println(" "+f.i+f.j+f.k); //f.i ne compile pas ni f.j
System.out.println(" "+c.i+c.j+c.k); // c.i ne compile pas et pourtant on est à l'intérieur de cousin
}
} |
m.j ne compile pas dans la première ligne parce que la variable est protected et qu'elle n'est ni dans une instance de classe du même package, ni dans l'instance elle-même, mais dans une autre instance.
pour f.i, i doit être considéré comme inexistante : elle n'est pas visible par Fille, donc pas plus par d'autres instances en dehors du package. Pareil pour c.i
En revanche, dans Maman, tu pourrais écrire :
1 2 3 4
|
public void testHeritage(Maman m, Fille f, Cousin c){
Maman filleCommeMaman = (Maman)f;
System.out.println(" "+filleCommeMaman.i); } |
Ici le type est Maman, qui est valide pour f (puisque Fille étend Maman), et i est une variable de Maman, donc accessible depuis une méthode de n'importe quelle instance de Maman.
Partager