如何防止修改某个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.asList
和Collections.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); }