Imaginez que j'ai 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!"; //!!!
Voilà donc le problème: j'ai accédé à un champ privé d'une classe de l'extérieur! Comment éviter cela? Je veux dire, comment puis-je rendre ce tableau immuable? Cela signifie-t-il qu'avec chaque méthode getter, vous pouvez progresser pour accéder au champ privé? (Je ne veux pas de bibliothèques telles que Guava. J'ai juste besoin de connaître la bonne façon de faire cela).
final
Object
Réponses:
Vous devez renvoyer une copie de votre tableau.
la source
Unmodifiable List
.Si vous pouvez utiliser une liste au lieu d'un tableau, Collections fournit une liste non modifiable :
la source
Collections.unmodifiableList(list)
comme affectation au champ, pour s'assurer que la liste n'est pas modifiée par la classe elle-même.String
est, mais s'ils sont modifiables, il faudra peut-être faire quelque chose pour empêcher l'appelant de les modifier.Le modificateur
private
protège uniquement le champ lui-même contre l'accès à partir d'autres classes, mais pas les références d'objets par ce champ. Si vous avez besoin de protéger un objet référencé, ne le donnez pas. Changementà:
ou pour
la source
Le
Collections.unmodifiableList
a déjà été mentionné -Arrays.asList()
étrangement non! Ma solution serait également d'utiliser la liste de l'extérieur et d'encapsuler le tableau comme suit:Le problème avec la copie du tableau est le suivant: si vous le faites à chaque fois que vous accédez au code et que le tableau est gros, vous créerez certainement beaucoup de travail pour le garbage collector. La copie est donc une approche simple mais vraiment mauvaise - je dirais "bon marché", mais chère en mémoire! Surtout lorsque vous avez plus de 2 éléments.
Si vous regardez le code source de
Arrays.asList
etCollections.unmodifiableList
il n'y a en fait pas grand chose de créé. Le premier encapsule simplement le tableau sans le copier, le second encapsule simplement la liste, rendant les modifications indisponibles.la source
immutableList
jusqu'au bout!Arrays.asList
etCollections.unmodifiableList
sont probablement moins chères pour les tableaux plus grands. Peut-être que quelqu'un peut calculer le nombre d'éléments nécessaires, mais j'ai déjà vu du code dans des boucles for avec des tableaux contenant des milliers d'éléments copiés juste pour empêcher la modification - c'est insensé!Vous pouvez également utiliser
ImmutableList
ce qui devrait être meilleur que la normeunmodifiableList
. La classe fait partie des bibliothèques Guava créées par Google.Voici la description:
Voici un exemple simple de son utilisation:
la source
Test
classe pour laisser la liste renvoyée inchangée . Vous devez vous assurer que celaImmutableList
est renvoyé et que les éléments de la liste sont également immuables. Sinon, ma solution devrait également être sûre.à ce point de vue, vous devez utiliser la copie de tableau système:
la source
clone
et n'est pas aussi concis.Vous pouvez renvoyer une copie des données. L'appelant qui choisit de modifier les données ne changera que la copie
la source
Le nœud du problème est que vous renvoyez un pointeur vers un objet mutable. Oups. Soit vous rendez l'objet immuable (la solution de liste non modifiable), soit vous renvoyez une copie de l'objet.
En règle générale, la finalité des objets ne protège pas les objets d'être modifiés s'ils sont mutables. Ces deux problèmes sont «embrasser des cousins».
la source
Renvoyer une liste non modifiable est une bonne idée. Mais une liste rendue non modifiable lors de l'appel à la méthode getter peut toujours être modifiée par la classe ou par les classes dérivées de la classe.
À la place, vous devez indiquer clairement à quiconque étend la classe que la liste ne doit pas être modifiée.
Donc, dans votre exemple, cela pourrait conduire au code suivant:
Dans l'exemple ci-dessus, j'ai rendu le
STRINGS
champ public, en principe vous pouvez supprimer l'appel de méthode, car les valeurs sont déjà connues.Vous pouvez également affecter les chaînes à un
private final List<String>
champ rendu non modifiable lors de la construction de l'instance de classe. L'utilisation d'une constante ou d'arguments d'instanciation (du constructeur) dépend de la conception de la classe.la source
Oui, vous devez renvoyer une copie du tableau:
la source