Portée des variables

Visibilité des données en Java

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

La portée des variables en PHP et Java repose sur les mêmes fondaments. Cependant, en Java elle est plus complexe et concerne plus d'aspects.

On distingue 3 niveaux de portée de variables en Java :

  1. public : accès publique. La variable est disponible depuis partout, par toutes les classes.
  2. protected : accès protégé. La variable n'est disponible qu'à l'intérieur d'une classe. Elle peut être donc visible pour les classes héritantes. Elle est aussi visible pour des classes non héritantes mais étant du même package.
  3. private : accès privé. La variable n'est disponible qu'à l'intérieur d'une classe. Héritée, elle n'est pas visible.
  4. Regardons ces cas sur une application :

    public class Visibility {
        public static void main(String[] args) {
            VisibilityEntity ve = new VisibilityEntity();
            ve.publicName = "public name";
            ve.setProtectedName("protected name");
            ve.setPrivateName("private name");
            ve.printNames();
            System.out.println("Protected name is visible outside VisibilityEntity because of the same package : " + ve.protectedName); 
        }
    }
    
    class VisibilityEntity {
      public String publicName;
      protected String protectedName;
      private String privateName;
      
        public void setProtectedName(String n) {
            protectedName = n;
        }
    
        public void setPrivateName(String n) {
            privateName = n;
        }
      
        public void printNames() {
            System.out.println("Public string : " + publicName);
            System.out.println("Protected string : " + protectedName);
            System.out.println("Private string : " + privateName);
        }
    }
    

    Voici le résultat :

    Public string : public name
    Protected string : protected name
    Private string : private name
    Protected name is visible outside VisibilityEntity because of the same package : protected name
    

    Si l'on tente d'accéder à privateName depuis la méthode main(), on reçoit en retour une erreur de compilation :

    Visibility.java:11: privateName has private access in VisibilityEntity
        System.out.println("Private name is visible outside VisibilityEntity because of the same package : " + ve.privateName);
    

    On remarque également une possibilité de récupérer directement la variable protectedName directement depuis main(). Tout cela grâce au fait que les deux se trouvent dans le même package.

    Afin de saisir une différence entre private et protected, créeons une classe héritante de VisibilityEntity :

    class VisibilityExtends extends VisibilityEntity {
        public VisibilityExtends(String n) {
            privateName = "private" + n;
            System.out.println("private from extended " + privateName);
            protectedName = "protected" + n;
            System.out.println("protected from extended " + protectedName);
        }
    }
    

    Elle sera appelée avec : VisibilityExtends vex = new VisibilityExtends("extends");

    Au moment de compilation on reçoit une erreur liée à la variable privée et non pas protégée :

    Visibility.java:41: privateName has private access in VisibilityEntity
        privateName = "private" + n;
        ^
    Visibility.java:43: privateName has private access in VisibilityEntity
        System.out.println(privateName);
    

    Afin de l'éviter, on doit déclarer une nouvelle fois la variable privateName dans la classe VisibilityExtends. On n'est pas obligés de faire la même chose avec la variable protégée car elle est héritable. La même nuance s'applique à des méthodes.

    Une grande différence avec PHP est une possibilité de préciser le niveau de visibilité à des classes :

    1. public : classe est visibile pour toutes les autres classes.
    2. friendly : niveau par défaut. Cette classe sera visible uniquement au sein d'un package.

    En ce qui concerne les classes, on a également une possibilité de définir une classe privée. Voici un exemple :

    afficher le code

    Voici le résultat sans la classe PrivateClass copiée dans PrivateExtended:

    Called from PrivateClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    PrivateClass prints private value(private String value)
    Called from ProtectedClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    ProtectedClass prints private value(private String value)
    New tests with PrivateExtended
    Called from PrivateClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    Called from ProtectedClass :
    publicString = public value
    privateString = null
    protectedString = protected value
    ProtectedClass prints null(private String value)
    Protected accessed from outside
    Called from ProtectedClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    ProtectedClass prints private value(private String value)
    

    Et si l'on décommente la déclaration du PrivateClass dans la classe héritant, on recevra :

    Called from PrivateClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    PrivateClass prints private value(private String value)
    Called from ProtectedClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    ProtectedClass prints private value(private String value)
    New tests with PrivateExtended
    Called from PrivateClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    Called from ProtectedClass :
    publicString = public value
    privateString = null
    protectedString = protected value
    ProtectedClass prints null(private String value)
    Protected accessed from outside
    Called from ProtectedClass :
    publicString = public value
    privateString = private value
    protectedString = protected value
    ProtectedClass prints private value(private String value)
    

    On peut donc tirer une conclusion que la portée des classes correspond à la portée des variables. Une classe interne privée ne sera pas accessible à une classe héritant. Une classe interne protégée le sera. On remarque également que les deux classes internes peuvent accéder à toutes les méthodes et attributs de la classe parent. Quand on devrait utiliser ces classes internes ? Voici les cas de figure où elles peuvent s'avérer utiles :
    - groupement logique : si une classe est utile uniquement pour une autre, on peut la traiter comme interne
    - encapsulation améliorée : dans le cas où l'on veut faire des attributs/méthodes accessibles uniquement pour une classe
    - plus de lisibilité : fabrication de plusieurs petites classes internes peut améliorer la visibilité globale du code ainsi que sa maintenabilité

    Afin d'appeler une classe protégée depuis l'extérieur, il faut d'abord initialiser la classe publique ou friendly. Ensuite on peut récupérer la classe protégée mais en indiquant bien qu'il s'agit d'une classe interne (dans notre exemple cela se traduit par PrivateExemple.ProtectedClass).

Bartosz KONIECZNY Informations sur le langage

Une question ? Une remarque ?

*

*

Un conseil PHP

Comment créer un signature key pour OAuth

Un signature key est l'un des deux composants qui constituent la signature de la requête OAuth. Il est composé de : - la clé secrète que le fournisseur (Google, Yahoo...) attribue au client, elle doit être toujours présente dans le signature key - le ticket secret qui est renvoyé à de différentes étapes de l'échange avec le web service du fournisseur; s'il est absent (comme lors de la récupération du ticket de la requête), il faut alors passer une chaîne de caractères vide Les deux paramètres doivent être encodés. Une méthode pour générer le signature key peut se présenter ainsi :

function setSignatureKey($tokenSecret)
{
  return str_replace('%7E', '~', rawurlencode($this->userData['secret'])).'&'.str_replace('%7E', '~', rawurlencode($tokenSecret));
}