我有一个私有内部类,它封装了一些功能。它填充了两个ArrayLists。我有ArrayLists的getter只返回私有变量。需要吸气剂吗?我可以只生成ArrayLists公共实例变量吗?什么是最佳做法?
public class OuterClass {
//Stuff the OuterClass does
private class InnerClass {
private ArrayList<String> array1;
private ArrayList<String> array2;
public InnerClass() {
//Init and do stuff w/ arrays
}
public ArrayList<String> getArray1() {
return array1;
}
public ArrayList<String> getArray2() {
return array2;
}
}
}
答案 0 :(得分:2)
是的,可以使Arraylist 公开,尽管最佳做法是使用getter。这允许您构建副作用,如
它还允许您在将来修改班级内部而不违反合同。
答案 1 :(得分:2)
最佳做法是提供吸气剂。这样可以避免某些人设置列表本身,将用户与基础代码更改隔离开来等等。
它们是否应该是一个不可修改的列表是一个单独的问题,只是取决于。
答案 2 :(得分:1)
您不会公开变量的原因是您要隐藏实现。如果从路径上的ArrayList切换到实际阵列会发生什么?你的所有代码都会中断。所以你写接口。
您可能还希望避免返回对数组的引用,而是提供以对类有意义的方式修改数组的方法。否则,使用您班级的人可能会进行您班级不期望的修改。
例如:
Foo foo = new Foo();
List list = foo.getArray();
list.add( new Object() );
此时,对象已被添加到您的Foo对象的内容中,并且您的foo对象没有任何机会检查该添加的有效性,拒绝添加,或以其他方式知道它在那里。如果您因性能原因决定延迟创建数组,那么您一直在访问null。吊杆。
答案 3 :(得分:0)
最佳做法是既不提供getter也不提供setter,而是您的对象不应公开其实现细节。
标准Java实践是拥有私有数据成员(a.k.a. fields)并提供getter和setter。
答案 4 :(得分:0)
这是一种方法,可以防止客户端通过getter提供的ArrayLists。请注意,尝试通过getter getResultsArray()返回的引用修改ArrayList应该引发异常:
package testCode;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
public class TestClass {
private ArrayList<String> resultsArray = Lists.newArrayList();
public void calculateResults(){
resultsArray.add("1");
resultsArray.add("2");
resultsArray.add("3");
}
public List<String> getResultsArray() {
return new ImmutableList.Builder<String>().addAll(resultsArray).build();
}
}
还有一个测试驱动程序:
package testCode;
public class TestMain {
public static void main(String[] args) {
TestClass testClass = new TestClass();
testClass.calculateResults();
for (String result : testClass.getResultsArray()) {
System.out.println(result);
}
try {
testClass.getResultsArray().add("fake result");
} catch (Exception e) {
System.out.println(e);
}
}
}
输出:
1
2
3
java.lang.UnsupportedOperationException
ImmutableList来自Google的Guava库。在这种情况下,ImmutableList实现List接口,但任何会立即更改列表的方法都会抛出UnsupportedOperationException。请注意,因为ImmutableList永远不会改变,所以实现的代码非常小,因为调整列表的普通List实现中的任何内容都不会在此处写入。非常有用,在这种情况下,我使用它来实现防御性编程,以防止我的TestClass用户调整我返回给他们的测试结果。
答案 5 :(得分:0)
假设外部类(定义内部类的内部)不是很大(如K行代码),那么定义getter是没有意义的。
理由:
内部类是私有的。 Getters将允许您对内部类进行(非常有限的)更改,而不会影响外部类。如果外部类足够小,那么受到getter可以防止泄漏的更改影响的代码范围也非常小。因此,先验地引入它们是没有意义的。如果需要 - 介绍它们,但在那之前 - 只需坚持使用更简单的代码。
当然,如果您重构代码并将内部类更改为(独立的)顶级类,那么您需要引入getter(或者 - 甚至更好 - 将设计更改为tell-not-问方案)
答案 6 :(得分:0)
最好通过Getters / Setters公开您的API以进行封装,通过接口类型声明对象也是一种很好的做法。
private List<E> list; // = new ArrayList<E>(); or initialize elsewhere
public List<E> getList() {
return list;
}
public void setList(List<E> list) {
this.list = list;
}