String est une classe immuable en Java. Une classe immuable est simplement une classe dont les instances ne peuvent pas être modifiées. Pourquoi le langage de programmation Java choisit-il de rendre les objets de la classe String immuables?
String est une classe immuable en Java. Une classe immuable est simplement une classe dont les instances ne peuvent pas être modifiées. Pourquoi le langage de programmation Java choisit-il de rendre les objets de la classe String immuables?
Réponses:
Ce problème est fortement lié à la notion de ce que signifie être une instance d'une classe. En termes strictement orientés objet, une classe a un invariant associé: un prédicat qui est toujours vrai à la sortie d'une méthode (publique) de la classe. Une telle notion est essentielle pour garantir que l'héritage est bien défini, par exemple (il fait partie du principe de substitution de Liskov ).
L'un des problèmes les plus pernicieux avec Java est qu'il est difficile d'empêcher le code client de casser les invariants de classe.
Par exemple, considérez la classe «ZipCode» suivante:
class ZipCode {
private String zipCode;
public ZipCode(String value){
if(!isValidZipCode(value))
throw new IllegalArgumentException();
zipCode = value;
assert(invariant());
}
public String get() { return zipCode; }
public boolean invariant() {
return isValidZipCode( zipCode );
}
}
Si String n'était pas immuable, il serait possible pour un utilisateur de ZipCode d'appeler `` get '' et de changer les caractères à tout moment ultérieur, brisant ainsi l'invariant et détruisant l'intégrité conceptuelle offerte par l'encapsulation du concept ZipCode.
Étant donné que ce type d'intégrité est essentiel pour garantir la validité des grands systèmes, cette réponse à votre question supplie vraiment la plus large de:
"Pourquoi Java ne prend-il pas en charge un analogue de const C ++, ou au moins ne propose-t-il pas de versions immuables de plusieurs de ses classes de bibliothèque?"
Des choses comme les chaînes et les dates sont naturellement des valeurs. En termes C ++, nous nous attendons à ce qu'ils aient un constructeur de copie, un opérateur d'affectation et un opérateur d'égalité, mais nous ne nous attendons jamais à prendre leur adresse. Par conséquent, nous ne nous attendons pas à ce qu'ils soient alloués individuellement sur le tas. Les méthodes virtuelles n'ont aucun sens.
Les objets de domaine sont naturellement des références. Ceux C ++ n'ont pas de constructeur de copie, d'opérateur d'affectation ou d'opérateur d'égalité (ils ne sont égaux que s'ils sont identiques). Nous pouvons prendre leur adresse et nous nous attendons à ce qu'ils soient alloués en tas. Les méthodes sont généralement virtuelles.
Java n'a pas de classes de valeur, seulement des classes de référence. Les valeurs sont truquées avec des objets immuables. Cela est vrai pour les chaînes, mais pas, malheureusement, pour les dates. La mutabilité des dates Java a causé des problèmes fréquents et est désormais obsolète. Les valeurs mutables ne peuvent pas être utilisées comme base pour un hachage, par exemple.
Java a été conçu pour permettre l'exécution de sous-sections du code d'un programme dans des environnements soumis à des contraintes de sécurité. La manière dont cette exigence a été mise en œuvre a été de définir un "SecurityManager" sur un thread qui a accès aux paramètres de certaines opérations critiques (par exemple, l'ouverture d'un fichier) et a demandé si l'opération devait être autorisée ou non. Si Java Strings était mutable, un programme pourrait contourner ces restrictions en créant deux threads, l'un qui effectuait une opération de fichier ouvert qui serait autorisé tandis que l'autre modifiait la chaîne dans laquelle il stockait le nom de fichier en un qui ne serait pas autorisé. Il est alors possible que le responsable de la sécurité lise la chaîne d'origine, accepte l'opération, qui sera transmise au code d'ouverture de fichier qui précédera ensuite l'ouverture du deuxième fichier (non autorisé).
Cette dernière possibilité rendrait toutes ces opérations plus lentes et aurait plus de chances que l'implémentation contienne des bogues, donc l'utilisation de chaînes immuables était la décision la plus judicieuse.
Plus généralement, les objets immuables sont utiles car ils permettent le partage sans avoir besoin de faire des copies défensives (ce qui peut être nécessaire même dans un code non critique pour la sécurité pour éviter les bugs lorsque les données source changent), donc même sans cette exigence, la décision serait toujours raisonnable.