• Aucun résultat trouvé

Les chaînes de caractères

}

Les objets n'ont pas de portée

Il faut bien garder à l'esprit le fait que seuls les identificateurs ont une por-tée. Dans le cas des primitives, l'identificateur pouvant être assimilé à l'ob-jet identifié, cela ne fait pas beaucoup de différence pour le programmeur.

En revanche, en ce qui concerne les objets, il en va différemment. Lors-qu'un handle est hors de portée, l'objet correspondant continue d'exister, et peut éventuellement être accessible grâce à un autre handle.

Les chaînes de caractères

En Java, les chaînes de caractères sont des objets. Ce sont des instances de la classe String. Cependant, leur nature nous oblige à en parler en même temps que des primitives.

Depuis les premiers langages de programmation, les chaînes de caractères ont posé des problèmes. En effet, s'il est facile de définir différents types numériques de format fixe, les chaînes de caractères ne peuvent être repré-sentées dans un format fixe car leur longueur peut varier de 0 à un nombre quelconque de caractères. Plusieurs approches sont possibles :

• Obliger le programmeur à déclarer la longueur de chaque chaîne. Il est alors possible de réserver une zone de mémoire correspondant au nom-bre de caractères déclaré. Le programmeur est ensuite linom-bre de modifier comme il le souhaite le contenu d'une chaîne, du moment qu'il ne la fait pas déborder. En cas de débordement, deux options sont possibles :

• Les données sont tronquées (avec ou sans message d'erreur).

• Les données débordent librement, ce qui conduit généralement à un plantage (au mieux, du programme, au pire, du système).

Cette méthode donne de bonnes performances, mais elle est peu sou-ple, et dangereuse dans certains cas.

• Utiliser des chaînes de longueur dynamique. Les chaînes sont créées avec la longueur correspondant à leur valeur d'initialisation. Si leur valeur est modifiée, leur longueur est automatiquement adaptée. Cette technique est très souple, mais peu efficace en termes de performances.

Java utilise une approche particulière. Les chaînes de caractères peuvent être initialisées à une valeur quelconque. Leur longueur est choisie en fonc-tion de leur valeur d'initialisafonc-tion. En revanche, leur contenu ne peut plus être modifié. Cette formule peut paraître restrictive, mais elle présente plu-sieurs avantages. En effet, la longueur des chaînes étant assurée de ne ja-mais varier, leur utilisation est très efficace en termes de performances. Par ailleurs, la restriction concernant l'immuabilité de leur contenu ne tient pas pour trois raisons :

• Dans la plupart des programmes, de très nombreuses chaînes de carac-tères sont utilisées, entre autres pour l'interface utilisateur, comme des constantes. (Java ne possède pas de constantes à proprement parler, comme nous le verrons plus loin.) Les messages qui doivent être affi-chés par le programme sont le plus souvent manipulés sous forme de chaînes de caractères, et la plupart de ces messages ne changent jamais.

Java dispose d'une autre classe, appelée StringBuffer, qui permet de gérer des chaînes dynamiques.

Si le programmeur veut traiter des instances de la classe String comme des chaînes dynamiques, il le peut. Il y a simplement une petite précau-tion à prendre.

Les chaînes de caractères existent aussi sous forme littérale. Pour utiliser une chaîne littérale, il suffit de la placer entre guillemets, comme dans l'exem-ple suivant :

System.out.println("Message à afficher");

Attention : Vous possédez un PC, vous utilisez certainement un éditeur sous Windows pour écrire vos programmes, alors que l'interpréteur Java fonctionne dans une fenêtre DOS. L'éditeur utilise donc le code ANSI alors que l'interpréteur utilise le code ASCII "étendu". Les caractères accentués que vous saisirez dans votre éditeur ne seront donc probablement pas affi-chés de manière correcte. (Rappelons que le code ANSI est englobé dans le code UNICODE utilisé par Java pour représenter les caractères. Le code ANSI constitue les 256 premiers caractères (codes 0 à 255) du code UNICODE. En revanche, le code ASCII ne comporte que 128 caractères (codes 0 à 127) identiques au code ANSI ; les codes 128 à 255 font partie des extensions qui peuvent différer selon les pays ou les environnements. Il est toutefois possible de sélectionner une extension particulière grâce aux pages de code du DOS.)

Les chaînes de caractères littérales peuvent contenir tous les caractères spé-ciaux que nous avons décrits à propos du type char :

\b arrière (backspace)

\f saut de page (form feed)

\n saut de ligne (new line)

\r retour chariot (carriage return)

\t tabulation horizontale (h tab)

\\ \ (backslash)

\' guillemet simple

\" guillemet double

\0oo caractère dont le code est oo en octal (le 0 est facultatif)

\uxxxx caractère dont le code Unicode est xxxx (en hexadécimal) Il est intéressant d'adapter notre programme Primitive3 pour tester le com-portement des chaînes de caractères. Voici le programme modifié, que nous avons appelé Chaines.java :

public class Chaines {

public static void main(String[] argv) { String chaineA = new String("Chaine 1");

System.out.println(chaineA);

String chaineB = chaineA;

System.out.println(chaineB);

chaineA = "Chaine 2";

System.out.println(chaineA);

System.out.println(chaineB);

} }

et voici le résultat obtenu :

Chaine 1 Chaine 1 Chaine 2 Chaine 1

Nous voyons que, bien qu'il s'agisse d'objets, les chaînes se comportent comme des primitives. Cela est dû au fait que les chaînes ne peuvent être modifiées. Ainsi, la ligne :

chaineA = "Chaine 2";

ne modifie pas la chaîne pointée par le handle chaineA, mais crée une nouvelle chaîne et lui attribue ce handle. Si, à ce moment, il n'existe pas d'autre handle pointant vers la chaîne d'origine, celle-ci devient inaccessi-ble et disparaîtra de la mémoire au prochain démarrage du garbage collector.

Dans notre cas, le handle chaine2 pointe encore vers la chaîne et celle-ci continue donc d'exister normalement, en gardant sa valeur originale.

Note : Les chaînes littérales sont créées par Java sous forme d'instances de la classe String. Voilà pourquoi il est possible d'exécuter une instruction comme celle ci-dessus. En fait, il ne s'agit pas d'affecter à l'objet chaineA une nouvelle valeur comme on le ferait pour une primitive, mais de le faire

pointer vers l'objet "Chaine 2". Chaque fois que vous placez une chaîne littérale dans votre programme, vous créez un objet instance de la classe String. Il s'agit, là encore, d'un objet anonyme, qui peut être utilisé immé-diatement et devenir ensuite indisponible et futur client du garbage collector, comme dans l'instruction :

System.out.println("Message à afficher");

ou se voir affecté un handle, comme dans l'instruction :

String message = "Message à afficher";

Dans notre programme Chaines, il était donc tout à fait inutile d'écrire :

String chaineA = new String("Chaine 1");

ce qui entraîne la création de deux objets dont l'un, anonyme, est immédia-tement abandonné. Il aurait été plus efficace d'écrire direcimmédia-tement :

String chaineA = "Chaine 1";

Constantes

Java ne comporte pas de constantes à proprement parler. Il est cependant possible de simuler l'utilisation de constantes à l'aide du mot clé final. Une variable déclarée final ne peut plus être modifiée une fois qu'elle a été initialisée.

L'usage de constantes pour représenter des valeurs qui ne doivent pas être modifiées présente deux avantages par rapport aux variables. Tout d'abord, c'est un bon moyen d'éviter les erreurs. Si, par inadvertance, vous modifiez la valeur d'une primitive déclarée final, le compilateur produira un message

d'erreur. Cela vous évitera de futures erreurs d'exécution pas toujours faci-les à détecter.

Par ailleurs, lorsque vous déclarez un élément final, le compilateur est à même d'optimiser le code compilé afin d'améliorer sa vitesse d'exécution.

Note : Il convient de remarquer que les variables déclarées final peuvent être initialisées lors de l'exécution, et non seulement lors de leur déclara-tion. Ainsi, elles ne sont constantes que pour une exécution et peuvent pren-dre une valeur différente à chaque exécution du programme (contrairement à ce qui était le cas pour la première version de Java, dans laquelle les variables finales devaient être initialisées lors de leur déclaration).

Utilisation de final avec des objets

L'utilisation de final n'est pas réservée aux primitives. Un handle d'objet peut parfaitement être déclaré final. Cependant, la contrainte ne s'applique alors qu'au handle, qui ne peut plus voir son affectation modifiée. L'objet, lui, reste modifiable.

Accessibilité

Les variables, comme les objets, les méthodes et les classes, ont également des accessibilités différentes. L'accessibilité définit dans quelles conditions on peut accéder à un élément ou, plus exactement, qui peut y accéder. Un objet peut être déclaré de façon à n'être accessible que depuis la classe qui le contient. On utilise pour cela le mot clé private. Les autres modes d'ac-cessibilité faisant appel à des notions que nous n'avons pas encore étudiées, nous les laisserons de côté pour l'instant.