Notes sur les "autorisations"


L'attribut static

Une variable declaree static appartient a une classe et non a une instance de classe. Par consequent une telle variable est partagee par toutes les instances de la classe.

Une variable declaree static est accessible:
  • soit par le nom de la classe.
  • soit via un handle sur une instance de la classe.

Une methode aussi peut etre declaree static. Dans ce cas, comme pour les variables declarees static, toutes les instances de la classe partagent le meme code pour la fonction. Tout comme les variables static, les methodes static sont accessibles soit via un handle sur une instance, soit directement via le nom de la classe.

Attention !
  • une methode static ne peut pas faire appel a des variables ou des methodes non static.
  • une methode static ne peut pas etre redefinie dans une classe derivee.


Exemple:
Fichier test.java
public class test
{
  public static void main(String[] argv)
  {
    TFinal F1 = new TFinal(1);
    System.out.println("\nF1 cree - ");
    TFinal.GetVar();
    TFinal F2 = new TFinal(2);
    System.out.println("\nF2 cree - ");
    TFinal.GetVar();
    
    F1.SetVar(11);
    F1.GetVar();
    F2.GetVar();
    F2.SetVar(22);
    F1.GetVar();
    F2.GetVar();
  }
}

class TFinal
{
  static int var;
  
  TFinal (int val)
  {
    System.out.println("\nvaleur de la variable static avant initialisation: " + var);
    var = val;
    System.out.println("\nvaleur de la variable static apres initialisation: " + var);
  }
  
  void SetVar (int val)
  {
    var = val;
  }

  static void GetVar()
  {
    System.out.println("var = " + var);
  }
}

Resultat apres execution:
valeur de la variable static avant initialisation: 0

valeur de la variable static apres initialisation: 1

F1 cree -
var = 1

valeur de la variable static avant initialisation: 1

valeur de la variable static apres initialisation: 2

F2 cree -
var = 2
var = 11
var = 11
var = 22
var = 22


L'attribut final

La valeur d'une variable declaree final ne peut etre modifiee apres initialisation. On peut les considerer comme des constantes. Le declarateur final en JAVA peut etre compare au declarateur const du C++.

Noter que les variables final sont tres utiles lors de la declaration des fonctions (cela permet de s'assurer que les arguments passes en argument ne seront pas modifies dans la fonction).

L'exemple suivant provoque deux erreurs de copilation:

Fichier test.java
public class test
{
  public static void main(String[] argv)
  {
    TFinal F1 = new TFinal(1);
    System.out.println("\nF1 cree - ");
    TFinal.GetVar();
    TFinal F2 = new TFinal(2);
    System.out.println("\nF2 cree - ");
    TFinal.GetVar();
    
    F1.SetVar(11);
    F1.GetVar();
    F2.GetVar();
    F2.SetVar(22);
    F1.GetVar();
    F2.GetVar();
  }
}

class TFinal
{
  static int var;
  final int toto = 15;
  
  TFinal (int val)
  {
    System.out.println("\nvaleur de la variable static avant initialisation: " + var);
    var = val;
    System.out.println("\nvaleur de la variable static apres initialisation: " + var);
    toto = 12; // provoque une erreur
  }
  
  void SetVar (final int val)
  {
    var = val;
    val = 0; // provoque une erreur !
  }

  static void GetVar()
  {
    System.out.println("var = " + var);
  }
}

Resultat de la compilation:

C:\programmes\java>javac test.java
test.java:31: Can't assign a value to a final variable: toto
    toto = 12; // provoque une erreur
    ^
test.java:37: Can't assign a second value to a blank final variable: val
    val = 0; // provoque une erreur !
    ^
2 errors

Les methodes peuvent aussi etre declarees final. Dans ce cas la methode ne peut pas etre redefinie dans une classe detivee.

L'exemple suivant provoque une erreur de compilation:

Fichier test.java
public class test
{
  public static void main(String[] argv)
  {
    Mere mere = new Mere();
    Fils fils = new Fils();
  }
}

class Mere
{
  Mere ()
  {
    System.out.println("\nCreation d'une classe mere.");
  }
  
  final void MFinal ()
  {
    System.out.println("\nMethode reserve a la classe mere");
  }
}

class Fils extends Mere
{
  Fils ()
  {
    System.out.println("\nCreation d'une classe fils.");
  }

  
  // provoque une erreur de compilation
  void MFinal ()
  {
    System.out.println("\nRedefinition pour le fils");
  }

}

Le resultat de la compilation est:

C:\programmes\java>javac test.java
test.java:31: The method void MFinal() declared in class Fils cannot override th
e final method of the same signature declared in class Mere. Final methods cann
ot be overridden.
  void MFinal ()
       ^
1 error

Une classe declaree final ne peut pas etre derivee.

L'exemple suivant provoque une erreur de compilation:

Fichier test.java
public class test
{
  public static void main(String[] argv)
  {
    Mere mere = new Mere();
    Fils fils = new Fils();
  }
}

final class Mere
{
  Mere ()
  {
    System.out.println("\nCreation d'une classe mere.");
  }
  
  void MFinal ()
  {
    System.out.println("\nMethode reserve a la classe mere");
  }
}

class Fils extends Mere
{
  Fils ()
  {
    System.out.println("\nCreation d'une classe fils.");
  }
}

Le resultat de la compilation est:

C:\programmes\java>javac test.java
test.java:23: Can't subclass final classes: class Mere
class Fils extends Mere
                   ^
1 error

L'attribut volatile

Une variable declaree volatile ne peut pas faire l'objet d'optimisation de la part du compilateur.

L'attribut abstract

Les methodes declarees abstract sont l'equivalent des fonctions virtuelles pures du C++. La methode est declaree mais n'est pas definie.

A quoi cela sert il ? Cela oblige a redefinir cette methode dans toutes les classes derivees de la classe comportant le methode abstract.

Attention !
  • Une classe comprtant une methode abstract doit etre declaree abstract.
  • Une classe abstract ne peut etre instanciee.
  • Une classe peut etre declaree abstract meme si elle ne comporte pas de methode abstract.
  • Une classe derivee d'une classe abstract ne peut etre instanciee que si elle a redefini toutes les methodes abstract de la classe dont elle derive. Dans le cas contraire la classe derivee doit elle aussi etre declaree abstract.

Le programme suivant provoque deux erreurs de compilation:

Fichier test.java
public class test
{
  public static void main(String[] argv)
  {
    // tentative d'instanciation d'une classe abstract
    Mere mere = new Mere();
  }
}

// Mere n'est pas declaree abstract
class Mere
{
  Mere ()
  {
    System.out.println("\nCreation d'une classe mere.");
  }
  
  abstract void MFinal ();
}

Le resultat de la compilation est:
C:\programmes\java>javac test.java
test.java:5: class Mere is an abstract class. It can't be instantiated.
    Mere mere = new Mere();
                ^
test.java:10: class Mere must be declared abstract. It does not define void MFin
al() from class Mere.
class Mere
      ^
2 errors

Correction:

Fichier test.java - CORRECTION
public class test
{
  public static void main(String[] argv)
  {
    Fils fils = new Fils();
    fils.MFinal();
  }
}

abstract class Mere
{
  Mere ()
  {
    System.out.println("\nCreation d'une classe mere.");
  }
  
  abstract void MFinal ();
}

class Fils extend Mere
{
  void MFinal ()
  {
    System.out.println("\nHello world !");
  }
}

A l'execution on observe le resultat suivant:

C:\programmes\java>java test

Creation d'une classe mere.

Hello world !


L'attribut public

Le mot cle public s'adresse:
  • Aux classes.
  • Aux attributs des classes.
  • Aux methodes des classes.
  • Aux interfaces.

Les elements declares public sont accessibles sans aucune restriction.

Attention !

Un fichier contenant un programme ne peut contenir qu'une seule classe declaree public (la classe contenant la fonction "main"). D'autre part le fichier doit porter le meme nom que la classe avec l'extension ".java".



L'attribut private

Cet attribut s'utilise pour les elements d'une classe. Tous les elements d'une classe declares private ne sont accessibles que depuis la classe qui les contient.

L'attribut protected

Cet attribut s'utilise pour les elements d'une classe. Les elements declares protected sont accessibles seulement par:
  • les methodes des classes appartenant au meme package.
  • les classes derivees.
  • les classes appartenant au meme package que les classes derivees.

Pour etre plus precis, voici un exemple:

PACKAGE pack1 - Fichier c1_pack1.java
package pack1;

public class c1_pack1
{
  protected int protected_var;

  public c1_pack1 ()
  {
    System.out.println("\nCreation d'une instance de la classe C1_Pack1");
  }
}

PACKAGE pack1 - Fichier c2_pack1.java
package pack1;

public class c2_pack1
{
  c1_pack1 objet = new c1_pack1();

  public c2_pack1 (final int i)
  {
    System.out.println("\nCreation d'une instance de la classe C2_Pack1");
    objet.protected_var = i;
  }
}

PACKAGE pack1 - Fichier c3_pack1.java
package pack1;

public class c3_pack1 extends c1_pack1
{
  public c3_pack1 ()
  {
    System.out.println("\nCreation d'une instance de la classe C3_Pack1");
  }

  public void SetVar (final int i)
  {
    protected_var = i;
  }
}

PACKAGE pack2 - Fichier c1_pack2.java
package pack2;

public class c1_pack2 extends pack1.c3_pack1
{
  public c1_pack2 ()
  {
    System.out.println("\nCreation d'une instance de la classe C1_Pack2");
    protected_var = 33;
    SetVar(5);
  }
}

PACKAGE pack2 - Fichier c2_pack2.java
package pack2;

public class c2_pack2 extends c1_pack2
{
  public c2_pack2 ()
  {
    System.out.println("\nCreation d'une instance de la classe C2_Pack2");
    protected_var = 100;
    SetVar(120);
  }
}

PACKAGE pack2 - Fichier c3_pack2.java
package pack2;

public class c3_pack2
{
  c2_pack2 obj = new c2_pack2();

  public c3_pack2 ()
  {
    System.out.println("\nCreation d'une instance de la classe C3_Pack2");
  }
  
  public void util()
  {
    // c2_pack2 derive de c1_pack2 qui derive elle meme de c3_pack1
    obj.SetVar(100);
  }
}

Fichier test.java
public class test
{
  public static void main (String[] atgv)
  {
     pack1.c1_pack1 obj1 = new pack1.c1_pack1();
     pack1.c2_pack1 obj2 = new pack1.c2_pack1(22);
     pack1.c3_pack1 obj3 = new pack1.c3_pack1();
     obj3.SetVar(44);
     pack2.c1_pack2 obj4 = new pack2.c1_pack2();
     pack2.c2_pack2 obj5 = new pack2.c2_pack2();
     obj5.SetVar(55);
     pack2.c3_pack2 obj6 = new pack2.c3_pack2();
  }
}

Commandes de compilation:

creation du package pack1
javac c1_pack1.java
move c1_pack1.class pack1\
javac c2_pack1.java
move c2_pack1.class pack1\
javac c3_pack1.java
move c3_pack1.class pack1\


creation du package pack2
javac c1_pack2.java
move c1_pack2.class pack2\
javac c2_pack2.java
move c2_pack2.class pack2\
javac c3_pack2.java
move c3_pack2.class pack2\


compilation du programme principal javac test.java