166 votes

Comment empêcher la modification d'un champ privé dans une classe ?

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!"; //!!!

Voici donc le problème : j'ai accédé à un champ privé d'une classe depuis l'extérieur ! Comment puis-je empêcher cela ? Je veux dire comment puis-je rendre ce tableau immuable ? Cela signifie-t-il qu'avec chaque méthode getter, vous pouvez vous frayer un chemin jusqu'à l'accès 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).

10 votes

En fait, le faire final fait empêcher la modification du champ . Cependant, empêcher la modification de la Object référencée par un champ est plus compliquée.

22 votes

Il y a un problème avec votre modèle mental si vous pensez qu'être capable de modifier un tableau auquel vous avez une référence stockée dans un champ privé est la même chose que d'être capable de modifier un champ privé.

46 votes

Si c'est privé, pourquoi l'exposer en premier lieu ?

380voto

sp00m Points 18767

Si vous pouvez utiliser une liste au lieu d'un tableau, Collections fournit une liste non modifiable :

public List<String> getList() {
    return Collections.unmodifiableList(list);
}

0 votes

Ajout d'une réponse qui utilise Collections.unmodifiableList(list) comme affectation au champ, pour s'assurer que la liste n'est pas modifiée par la classe elle-même.

0 votes

Je me demandais juste, si vous décompilez cette méthode vous obtenez beaucoup de nouveaux mots-clés. Est-ce que cela ne nuit pas aux performances lorsque getList() est souvent utilisé. Par exemple dans le code de rendu.

2 votes

Notez que cela fonctionne si les éléments des tableaux sont immuables en eux-mêmes comme String mais s'ils sont mutables, il faudra peut-être faire quelque chose pour empêcher l'appelant de les modifier.

164voto

OldCurmudgeon Points 16615

Vous devez renvoyer un copie de votre tableau.

public String[] getArr() {
  return arr == null ? null : Arrays.copyOf(arr, arr.length);
}

123 votes

J'aimerais rappeler aux gens que, bien que cette réponse ait été votée comme étant la bonne réponse à la question, l'équipe d'experts de l'Union européenne n'a pas été en mesure de répondre à cette question. la meilleure solution au problème est en fait comme sp00m dit - pour renvoyer un Unmodifiable List .

48 votes

Pas si vous avez besoin de retourner un tableau.

8 votes

En fait, le la meilleure solution au problème discuté est souvent comme le dit @MikhailVladimirov : - fournir ou retourner une voir du tableau ou de la collection.

45voto

Mikhail Vladimirov Points 7244

Modificateur private protège uniquement le champ lui-même contre l'accès à partir d'autres classes, mais pas les objets référencés par ce champ. Si vous avez besoin de protéger l'objet référencé, il suffit de ne pas le donner. Modifier

public String [] getArr ()
{
    return arr;
}

à :

public String [] getArr ()
{
    return arr.clone ();
}

ou à

public int getArrLength ()
{
    return arr.length;
}

public String getArrElementAt (int index)
{
    return arr [index];
}

5 votes

Cet article ne s'oppose pas à l'utilisation du clone sur les tableaux, mais uniquement sur les objets qui peuvent être sous-classés.

28voto

michael_s Points 1593

En Collections.unmodifiableList a déjà été mentionné - le Arrays.asList() étrangement non ! Ma solution serait également d'utiliser la liste de l'extérieur et d'envelopper le tableau comme suit :

String[] arr = new String[]{"1", "2"}; 
public List<String> getList() {
    return Collections.unmodifiableList(Arrays.asList(arr));
}

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 grand, vous allez certainement créer beaucoup de travail pour le ramasseur de déchets. La copie est donc une approche simple mais vraiment mauvaise - je dirais "bon marché", mais coûteuse en mémoire ! Surtout lorsque vous avez plus de deux éléments.

Si vous regardez le code source de Arrays.asList y Collections.unmodifiableList il n'y a en fait pas beaucoup de création. La première ne fait qu'envelopper le tableau sans le copier, la seconde n'enveloppe que la liste, rendant les modifications de celle-ci indisponibles.

0 votes

Vous supposez ici que le tableau y compris les cordes est copié à chaque fois. Ce n'est pas le cas, seules les références aux chaînes immuables sont copiées. Tant que votre tableau n'est pas énorme, la surcharge est négligeable. Si le tableau est énorme, optez pour les listes et les chaînes immuables. immutableList jusqu'au bout !

0 votes

Non, je n'ai pas fait cette supposition - où ? Il s'agit des références qui sont copiées - peu importe qu'il s'agisse d'une chaîne ou de tout autre objet. Je dis juste que pour les grands tableaux, je ne recommanderais pas de copier le tableau et que la fonction Arrays.asList y Collections.unmodifiableList Les opérations sont probablement moins chères pour les plus grandes matrices. Peut-être que quelqu'un peut calculer combien d'éléments sont nécessaires, mais j'ai déjà vu du code dans des for-loops avec des tableaux contenant des milliers d'éléments copiés juste pour éviter toute modification - c'est insensé !

6voto

iTech Points 7948

Vous pouvez également utiliser ImmutableList ce qui devrait être meilleur que la norme unmodifiableList . Le cours fait partie de Goyave des bibliothèques qui ont été créées par Google.

Voici la description :

Contrairement à Collections.unmodifiableList(java.util.List), qui est une vue d'une collection séparée qui peut toujours changer, une instance de ImmutableList contient ses propres données privées et ne changera jamais.

Voici un exemple simple de son utilisation :

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public ImmutableList<String> getArr() 
  {
    return ImmutableList.copyOf(arr);
  }
}

0 votes

Utilisez cette solution si vous ne peut pas faire confiance à la Test pour laisser la liste retournée inchangée . Vous devez vous assurer que ImmutableList est retourné, et que les éléments de la liste sont également immuables. Sinon, ma solution devrait être sûr aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X