Comment puis-je empêcher la modification d'un champ privé dans une classe?
Imaginer que j'ai de cette classe:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Maintenant, j'ai une autre classe qui utilise la classe ci-dessus:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
Donc, c'est le problème: j'ai consulté un domaine privé d'une classe à partir de l'extérieur!
Comment puis-je éviter cela? Je veux dire, comment puis-je faire de ce tableau immuable? Est-ce à dire que chaque méthode de lecture vous pouvez travailler votre chemin jusqu'à accéder à la zone privée? (Je ne veux pas de bibliothèques comme la Goyave. J'ai juste besoin de connaître la bonne façon de le faire).
- faire
final
- En fait, le rendant
final
empêche la modification du champ. Toutefois, la prévention de la modification de laObject
visé par un champ est plus compliqué. - Il y a un problème avec votre modèle mental si vous pensez être en mesure de modifier un tableau pour lequel vous avez une référence stockée dans un champ privé est la même chose que d'être en mesure de modifier un champ privé.
- Si c'est le privé, pourquoi l'exposer en premier lieu?
- Les deux OldCurmudgeon et sp00m anwsers sont à droite. À utiliser dépend de la situation. Je vous recommande de lire Efficace Java - Item 13: Minimiser l'accessibilité des classes et des membres.
- Il m'a fallu un certain temps pour comprendre cela, mais il améliore toujours mon code quand j's'assurer que toutes les structures de données sont entièrement encapsulés à l'intérieur de leur objet-à-dire il n'existe aucun moyen pour "Obtenir" votre "arr", au lieu de faire qu', vous devez à l'intérieur de la classe ou de fournir un itérateur.
- Je propose l'édition du titre de
Prevent modification to a private array field?
. - Je vois que personne n'a mentionné Josh Bloch Effectif de Java -
Item 39: Make defensive copies when needed
- Est ce que quelqu'un d'autre aussi surpris de voir pourquoi cette question a eu tellement d'attention?
- Je n'ai pas l'upvotes pour Erik Reppen commentaire. L'encapsulation de données ne signifie pas que vous ne pouvez pas exposer l'état interne, mais il doit s'assurer que l'instance de contrôle de l'état interne (par exemple en renvoyant uniquement en lecture seule des valeurs ou des copies des valeurs stockées).
Vous devez vous connecter pour publier un commentaire.
Vous devez renvoyer un copie de votre tableau.
Unmodifiable List
.unmodifiableList
peut sembler, il retourne en fait un inmodifiable vue d'une éventuellement modifiables liste.java.lang.String
peut être gâché par l'intermédiaire de la réflexion. Rappelez-vous: l'encapsulation est de protéger les code de code, et non pas sur la protection de la code de des codeurs.Si vous pouvez utiliser une Liste au lieu d'un tableau, Collections fournit une liste inmodifiable:
Collections.unmodifiableList(list)
comme la cession du terrain, assurez-vous que la liste n'est pas modifiée par la classe elle-même.String
est bien, mais si ils sont mutables quelque chose pourrait être fait pour empêcher l'appelant de les modifier.Modificateur
private
ne protège que le champ lui-même d'être accessible à partir d'autres classes, mais pas l'objet de références en ce domaine. Si vous avez besoin de protéger l'objet référencé, il suffit de ne pas le donner. Changementà:
ou à
clone()
?La
Collections.unmodifiableList
a déjà été mentionné - laArrays.asList()
étrangement pas! Ma solution serait également utiliser la liste de l'extérieur et envelopper le tableau comme suit:Le problème avec la copie du tableau est: si vous le faites à chaque fois que vous accédez le code et le tableau est grand, vous allez créer beaucoup de travail pour le garbage collector pour vous. Si la copie est un simple, mais c'est une mauvaise approche, je dirais, "bon marché", mais de mémoire-cher! Surtout quand vous êtes en avoir plus que juste 2 éléments.
Si vous regardez le code source de
Arrays.asList
etCollections.unmodifiableList
il n'y a effectivement pas beaucoup créé des. Le premier juste enveloppe le tableau sans le copier, le deuxième, juste encapsule la liste, faire des changements indisponible.immutableList
tout le chemin!Arrays.asList
etCollections.unmodifiableList
opérations sont probablement moins cher pour les plus grands tableaux. Peut-être que quelqu'un peut calculer combien d'éléments sont nécessaires, mais j'ai déjà vu code de boucles avec des tableaux contenant des milliers d'éléments copiés pour empêcher toute modification. - c'est de la folie!Vous pouvez également utiliser
ImmutableList
qui devrait être mieux que la normeunmodifiableList
. La classe fait partie de Goyave bibliothèques qui a été créer par Google.Voici la description:
Voici un exemple simple de la façon de l'utiliser:
Test
classe de quitter la liste retournée intacte. Vous devez vous assurer queImmutableList
est retourné, et que les éléments de la liste sont immuables ainsi. Sinon, ma solution devrait être à l'abri ainsi.à ce point de vue, vous devez utiliser le système de tableau de copie:
clone
, et n'est pas aussi concis.Vous pouviez retourner une copie des données. Le visiteur qui choisit de changer les données seront seulement la modification de la copie
Là le cœur du problème, c'est que vous êtes de retour d'un pointeur vers un objet mutable. Oups. Soit vous effectuez le rendu de l'objet immuable (le inmodifiable liste de solution) ou vous retourner une copie de l'objet.
D'une manière générale, la finalité des objets ne permet pas de protéger les objets d'être modifiées si elles sont mutables. Ces deux problèmes sont "kissing cousins."
Retour d'un inmodifiable liste est une bonne idée. Mais une liste qui est faite inmodifiable lors de l'appel à la méthode de lecture peut toujours être modifié par la classe ou à des classes dérivées de la classe.
Au lieu de cela, vous devriez faire comprendre à quelqu'un qui étend la classe que la liste ne doit pas être modifié.
Donc dans votre exemple, il pourrait conduire à la suite du code:
Dans l'exemple ci-dessus, j'ai fait le
STRINGS
domaine public, en principe, on pourrait faire disparaître avec l'appel de la méthode, ainsi que les valeurs sont déjà connus.Vous pouvez également affecter les cordes pour un
private final List<String>
field inmodifiable lors de la construction de l'instance de classe. À l'aide d'une constante ou d'instanciation des arguments (du constructeur) dépend de la conception de la classe.Oui, vous devez nous retourner une copie de la matrice: