Programmation pour le TAL

Membres et méthodes statiques

Lecture : champs et méthodes de classes: chapitre 6, section 7 du livre "Programmer en Java"

Membres statiques

Jusqu'ici, nous avons déclaré, dans une classe donnée, des membres qui ne portaient pas le modifieur static. Chaque instance (objet) de la classe avait son propre membre/sa propre valeur pour ce membre. Un membre statique est un membre de classe (une sorte de "variable globale" définie au sein d'une classe) :

Si on imagine que l'on veuille, à un moment donné de l'exécution, compter le nombre d'objets géométriques créés, déclarer un integer dans la méthode main() et incrémenter ce nombre ne suffit pas : il n'y a pas que dans le main() que l'on créé des objets. Ces objets peuvent être créés ailleurs, hors du contrôle du programmeur qui écrit la méthode main() : on ne maîtrise pas ce qui se passe dans toutes les classes (des objets peuvent être créés dans des classes que l'on utilise sans les avoir implémentées). On peut dans ce cas déclarer un entier statique (exceptionnellement, et temporairement, "publique") dans la classe GeomObject. Dans cet exemple, on initialise la valeur de l'entier à 0.

    public class GeomObject
    {
        public  static int    nbCreatedObjects = 0;           // nb d'objets créés - membre statique, existe de manière unique
	private        String objName          = "anonymous"; // membre non statique, existe pour chaque objet instancié
    }

Au sein de la classe GeomObject (et classes dérivées), on peut accéder à nbCreatedObjects en écrivant simplement son nom (comme pour un membre non statique) :

    public class Circle extends GeomObject
    {
	public Circle ()
	{
	    nbCreatedObjects++;
	}
    }

Mais, dans une autre classe (e.g. TestGeomObjects), comme un membre statique exisite indépendamment de tout objet instancié, et comme c'est un membre "de classe", on n'écrit pas nomObjet.nomMembre pour y accéder, mais nomClasse.nomMembre. Pour nbCreatedObjects, on écrira GeomObject.nbCreatedObjects.

    public class TestGeomObjects
    {
	public static void main (String args[])
	{
	    System.out.println(GeomObject.nbCreatedObjects);
	    // possible car nbCreatedObjects existe même aucun objet n'a été instancié 
	    // (affiche 0)
	}
    }

Méthodes statiques

De la même manière qu'il existe des membres statiques, il existe des méthodes statiques que l'on n'invoque pas sur un objet donné, mais sur une classe. Il existe différents cas pour lesquels l'utilisation de méthodes statiques est soit utile, soit nécessaire, que nous décrivons ci-dessous.

Méthodes "utilitaires"

Pour connaître la valeur maximale entre deux nombres, il existe dans la classe Math de l'API plusieurs méthodes max() qui prennent en paramètre deux entiers ou deux flottants. Cette m'éthode se s'invoque pas sur un objet en particulier, mais sur la classe Math :

    System.out.println (Math.max (3.2, 6.4));
    System.out.println (Math.max (4, 2));

Dans la classe String, il existe une méthode statique valueOf() qui prend un argument de type Object et renvoie :


Cette méthode permet d'afficher une chaîne de caractère quel que soit l'objet, même s'il est null, sans provoquer un NullPointerException qui résulterait de l'invocation de la méthode toString() sur un référence nulle. Si cette méthode n'existait pas, on serait obligé d'écrire, partout ou l'on en a besoin :

    if (obj == null)
        System.out.println ("null");
    else
        System.out.println (obj.toString());

Une autre manière d'écrire cela, plus "geek", mais moins lisible est :
System.out.println ((obj == null) ? "null" : obj.toString());
(inutile de retenir cette syntaxe, mais il faut pouvoir la déchiffrer si vous pouvez la rencontrez).

Méthodes statiques pour l'accès aux membres statiques

Une autre bonne raison de créer des méthodes statiques réside dans le besoin d'accéder aux membres statiques. Plus haut, nous avons déclaré un membre statique publique pour introduire cette notion. Mais il n'y a aucune bonne raison (dans ce cas) de rendre l'accès à ce membre publique. On peut écrire pour les membres de classes les mêmes méthodes (getters/setters) que pour les membres non statiques.

    public class GeomObject
    {
        private static int nbCreatedObjects = 0

        public static int getNbCreatedObjects ()
        {     
            return nbCreatedObjects;
        }      

        // méthode pas nécessairement pertinente dans cet exemple
        public static void setNbCreatedObjects (nb)
        {
            // attention : ici, pas de this.nbCreatedObjects possible
            // this = "objet sur lequel on a invoqué la méthode".
            // Ici, on invoque une méthode "de classe"
            // => on ne l'invoque pas sur un objet
            nbCreatedObjects = nb;
        }
      
        public static void incNbCreatedObjects ()
        {
            // accès au sein de la classe : pas besoin d'écrire GeomObject.nbCreatedObjects++
            nbCreatedObjects++;
        }      
    }

    public class TestGeomObjects
    {
	public static void main (String args[])
	{
	    System.out.println(GeomObject.getNbCreatedObjects());
	    // (affiche 0)
            GeomObject.incNbCreatedObjects ();
            GeomObject.incNbCreatedObjects ();
	    System.out.println(GeomObject.getNbCreatedObjects());
	    // (affiche 2)

            GeomObject.setNbCreatedObjects (0);
	    System.out.println(GeomObject.getNbCreatedObjects());
	    // (affiche 0)
        }
    } 
    

Méthodes utilitaires, suite

Lorsque vous souhaitez regrouper les traitements récurrents que vous effectuez sur les instances d'une classe que vous avez conçue, le plus logique est souvent d'écrire ces traitements dans cette classe. Mais lorsque vous effectuez ces traitements récurrents sur une classe dont vous êtes l'utilisateur et non le concepteur (et si vous n'avez pas accès aux sources de cette classe), vous pouvez créer une classe dédiée à ces traitements.

Pour le projet d'extraction des triplets syntaxiques, vous pouvez être amenés à tester si un token est un verbe conjugué, un verbe à l'infinitif, un verbe tout court, si un token est sujet, etc. Vous pouvez ajouter des méthodes directement dans la classe Token :

    public boolean isVerb ()
    {
	return getPOS().startsWith("V");
    }
	
    public boolean isInflectedVerb ()
    {
	return ???;
    }
	
    public boolean isInfinitive ()
    {
    	return ???;
    }

    public boolean isSuj ()
    {
    	return getDepLabel().equals ("suj");
    }

À l'extérieur de la classe (e.g. dans DependenciesBuilder), vous pouvez invoquer ces méthodes sur des instances particulières de Token : if (monToken.isSuj ()) {...}

Si l'on imagine que vous n'ayez pas accès aux sources de la classe Token, vous pouvez créer une classe qui effectue les mêmes traitements :

    package sajous.litl.token;

    public class TokenUtils
    {
	public static boolean isSuj (Token token)
	{
		return token.getDepLabel().equals("suj");
	}
	
	public static boolean isCommonNoun (Token token)
	{
		return token.getPOS ().equals("NC");
	}

	public static boolean isVerb (Token token)
	{
		return token.getPOS().startsWith("V");
	}
	
	public Token getGovernor (Token token, Sentence sent)
	{
		Token result = null;
		
		// affectation a result du gouverneur de token
		
		return result;		
	}
	
	public void relemmatize (Token token)
	{
		if (token.getLemma().equals("_"))
		{
			// appliquer heuristique pour deviner le lemme 
		}
	}
    }
Dans la classe DependenciesBuilder :
  Sentence sent = reader.getSentence(); 
  Token firstToken = sent.getToken(0); // declenche une exception (ArrayOutOfBoundException) si la phrase est vide

  System.out.println (TokenUtils.isNoun(firstToken));
  System.out.println ("Gouverneur : " + TokenUtils.getGovernor (firstToken, sent);

Représentation UML

Dans un diagramme de classes UML, le nom des membres et les méthodes statiques est souligné. Sous Dia, il existe (pour les membres/attributs et pour les méthodes) une case à cocher : "visibilité de classe" ou "class scope".
À noter : bug possible du logiciel, selon les versions, e.g. dans ma version (0.97), seules les méthodes statiques apparaissent soulignées et pas les membres.

Retour page séance 7 ]

Mention légale ]