如何防止修改某个class级的私人领域?

想象一下,我有这个类:

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

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

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

所以这就是问题所在:我从外面访问了一个class的私人领域! 我怎样才能防止这个? 我的意思是我怎样才能使这个数组不可变? 这是否意味着每一个吸气的方法,你可以用自己的方式来访问私人领域? (我不想要像Guava这样的图书馆,我只需要知道正确的方法来做到这一点)。

您必须返回arrays的副本

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

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

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

private修饰符仅保护字段本身不被其他类访问,但不保护该字段的对象引用。 如果你需要保护被引用的对象,就不要放弃。 更改

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

至:

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

或者

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

Collections.unmodifiableList已经被提到 – Arrays.asList()奇怪的不是! 我的解决scheme也是从外部使用列表并包装数组,如下所示:

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

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

如果你看一下Arrays.asListCollections.unmodifiableList的源代码, Arrays.asList并没有太多的创build。 第一个只包装数组而不复制它,第二个只包装列表,对其进行更改不可用。

你也可以使用ImmutableList ,它应该比标准的unmodifiableList更好。 该课程是由Google创build的Guava图书馆的一部分。

这里是描述:

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

下面是一个简单的例子:

 public class Test { private String[] arr = new String[]{"1","2"}; public ImmutableList<String> getArr() { return ImmutableList.copyOf(arr); } } 

在这个angular度来看你应该使用系统数组拷贝:

 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; } } 

您可以返回数据的副本。 select更改数据的主叫方只会更改副本

 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; } } 

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

一般来说,对象的终结并不能防止对象在可变的情况下被改变。 这两个问题是“亲吻表亲”。

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

相反,你应该向所有扩展名单的人说清楚,不应该修改名单。

所以在你的例子中可能会导致下面的代码:

 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; } } 

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

您也可以将这些string分配给在构造类实例期间不可修改的private final List<String>字段。 使用常量或实例化参数(构造函数)取决于类的devise。

 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; } } 

是的,你应该返回一个数组的副本:

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