java 如何防止修改类中的私有字段?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14809293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 17:27:50  来源:igfitidea点击:

How do I prevent the modification of a private field in a class?

javaarraysoopclass

提问by Hossein

Imagine that I have this class:

想象一下,我有这个类:

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

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

Now, I have another class that uses the above class:

现在,我有另一个使用上述类的类:

Test test = new Test();
test.getArr()[0] ="some value!"; //!!!

So this is the problem: I have accessed a private field of a class from outside! How can I prevent this? I mean how can I make this array immutable? Does this mean that with every getter method you can work your way up to access the private field? (I don't want any libraries such as Guava. I just need to know the right way to do this).

所以这就是问题所在:我从外部访问了一个类的私有字段!我怎样才能防止这种情况?我的意思是如何使这个数组不可变?这是否意味着您可以使用每种 getter 方法来访问私有字段?(我不想要任何诸如 Guava 之类的库。我只需要知道正确的方法即可)。

采纳答案by OldCurmudgeon

You must return a copyof your array.

您必须返回数组的副本

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

回答by sp00m

If you can use a List instead of an array, Collections provides an unmodifiable list:

如果您可以使用 List 而不是数组,Collections 提供了一个不可修改的列表

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

回答by Mikhail Vladimirov

Modifier privateprotects only field itself from being accessed from other classes, but not the object references by this field. If you need to protect referenced object, just do not give it out. Change

修饰符private仅保护字段本身不被其他类访问,但不保护此字段的对象引用。如果您需要保护引用的对象,请不要将其泄露出去。改变

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

to:

到:

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

or to

或者

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

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

回答by michael_s

The Collections.unmodifiableListhas already been mentioned - the Arrays.asList()strangely not! My solution would also be to use the list from the outside and wrap the array as follows:

Collections.unmodifiableList已经提到-的Arrays.asList()奇怪不是!我的解决方案也是使用外部列表并按如下方式包装数组:

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

The problem with copying the array is: if you're doing it every time you access the code and the array is big, you'll create a lot of work for the garbage collector for sure. So the copy is a simple but really bad approach - I'd say "cheap", but memory-expensive! Especially when you're having more than just 2 elements.

复制数组的问题是:如果每次访问代码时都这样做,并且数组很大,那么肯定会为垃圾收集器创建大量工作。所以副本是一种简单但非常糟糕的方法 - 我会说“便宜”,但内存昂贵!尤其是当您拥有不止 2 个元素时。

If you look at the source code of Arrays.asListand Collections.unmodifiableListthere is actually not much created. The first just wraps the array without copying it, the second just wraps the list, making changes to it unavailable.

如果你看看源代码Arrays.asList,并Collections.unmodifiableList有其实不多创建。第一个只是包装数组而不复制它,第二个只是包装列表,使其无法更改。

回答by iTech

You can also use ImmutableListwhich should be better than the standard unmodifiableList. The class is part of Guavalibraries that was create by Google.

您还可以使用ImmutableListwhich 应该比标准更好unmodifiableList。该类是由 Google 创建的Guava库的一部分。

Here is the description:

这是描述:

Unlike Collections.unmodifiableList(java.util.List), which is a view of a separate collection that can still change, an instance of ImmutableList contains its own private data and will never change

与 Collections.unmodifiableList(java.util.List) 不同,它是一个仍然可以改变的单独集合的视图,ImmutableList 的实例包含它自己的私有数据并且永远不会改变

Here is a simple example of how to use it:

这是一个如何使用它的简单示例:

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

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

回答by G M Ramesh

at this point of view you should use system array copy:

从这个角度来看,您应该使用系统数组副本:

public String[] getArr() {
   if (arr != null) {
      String[] arrcpy = new String[arr.length];
      System.arraycopy(arr, 0, arrcpy, 0, arr.length);
      return arrcpy;
   } else
      return null;
   }
}

回答by ncmathsadist

The nub of the problem is that you are returning a pointer to a mutable object. Oops. Either you render the object immutable (the unmodifiable list solution) or you return a copy of the object.

问题的关键在于您正在返回一个指向可变对象的指针。哎呀。要么将对象呈现为不可变(不可修改的列表解决方案),要么返回对象的副本。

As a general matter, finality of objects does not protect objects from being changed if they are mutable. These two problems are "kissing cousins."

一般来说,如果对象是可变的,对象的终结性并不能保护对象不被更改。这两个问题是“亲亲表亲”。

回答by artfullyContrived

You could return a copy of the data. The caller who chooses to change the data will only be changing the copy

您可以返回数据的副本。选择更改数据的调用者只会更改副本

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

    public String[] getArr() {

        String[] b = new String[arr.length];

        System.arraycopy(arr, 0, b, 0, arr.length);

        return b;
    }
}

回答by Maarten Bodewes

Returning an unmodifiable list is a good idea. But a list that is made unmodifiable during the call to the getter method can still be changed by the class, or classes that are derived from the class.

返回一个不可修改的列表是一个好主意。但是在调用 getter 方法期间不可修改的列表仍然可以由类或从类派生的类进行更改。

Instead you should make it clear to anybody that extends the class that the list should not be modified.

相反,您应该向扩展该类的任何人明确表示不应修改该列表。

So in your example it could lead to the following code:

因此,在您的示例中,它可能会导致以下代码:

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    public static final List<String> STRINGS =
        Collections.unmodifiableList(
            Arrays.asList("1", "2"));

    public final List<String> getStrings() {
        return STRINGS;
    }
}

In the above example I've made the STRINGSfield public, in principle you could do away with the method call, as the values are already known.

在上面的示例中,我将STRINGS字段设为公开,原则上您可以取消方法调用,因为这些值已经知道了。

You could also assign the strings to a private final List<String>field made unmodifiable during construction of the class instance. Using a constant or instantiation arguments (of the constructor) depends on the design of the class.

您还可以将字符串分配给private final List<String>在构建类实例期间不可修改的字段。使用常量或实例化参数(构造函数的)取决于类的设计。

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    private final List<String> strings;

    public Test(final String ... strings) {
        this.strings = Collections.unmodifiableList(Arrays
                .asList(strings));
    }

    public final List<String> getStrings() {
        return strings;
    }
}

回答by kofemann

Yes, you should return a a copy of the array:

是的,您应该返回数组的副本:

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