Java不使用static时如何跨类调用protected ArrayList供类内所有方法使用
可以,不需要static修饰也能实现跨类共用同一个protected修饰的ArrayList实例,核心是先满足protected的访问规则,再保证所有方法引用到的是同一个ArrayList实例即可。
- protected访问权限边界:protected修饰的非static成员,仅允许三类场景访问:
- 同一个包下的所有类,可直接通过实例访问
- 不同包下的子类,可访问自身继承到的该成员,或通过自身子类类型的实例访问
- 成员所在类本身可直接访问
- 非static成员归属逻辑:非static成员属于对象实例,不属于类,要跨类、跨方法共用同一个非static成员,本质是所有使用位置都拿到同一个对象实例持有的成员引用即可,和是否加static没有必然关系。
场景1:两个类在同一个包下
这是最简单的场景,直接在使用类(注:Java类名规范建议首字母大写,原示例中another建议改为Another)中持有同一个ArrayListClass实例作为成员变量,所有方法都通过这个实例访问someClass即可,示例代码:
// 和ArrayListClass定义在同一个包下 public class Another { // 持有唯一的ArrayListClass实例,所有方法共用这一个 private final ArrayListClass listHolder = new ArrayListClass(); private void method1() { // 直接访问同一个list listHolder.someClass.add(new SomeClass()); } private void method2() { // 和method1操作的是同一个list实例 listHolder.someClass.remove(0); } public void method3() { System.out.println("当前list长度:" + listHolder.someClass.size()); } }
也可以直接把list引用存为Another的成员变量,不用每次链式调用,写法更简洁:
public class Another { private final ArrayList<SomeClass> sharedList; public Another() { // 构造时只拿一次引用,后续所有方法共用 this.sharedList = new ArrayListClass().someClass; } // 三个方法里直接操作sharedList即可 }
场景2:两个类在不同包下
这时候有两种可选实现方式:
方式1:让Another成为ArrayListClass的子类
不同包下只有子类能访问protected成员,继承后父类的someClass会作为子类实例的成员存在,只要用的是同一个Another实例,所有方法访问的就是同一个list:
// 注意导入ArrayListClass的包路径 import com.yourpackage.ArrayListClass; public class Another extends ArrayListClass { private void method1() { // 直接访问继承到的someClass,属于当前实例 someClass.add(new SomeClass()); } private void method2() { someClass.clear(); } public void method3() { for (SomeClass sc : someClass) { // 遍历逻辑 } } }
注意:这种方式下如果new多个Another实例,每个实例的someClass是独立的,要共用同一个list必须保证所有操作都基于同一个Another实例。
方式2:不继承,通过ArrayListClass提供的公开方法获取list引用
如果不想用继承,可以在ArrayListClass里加一个public的getter方法暴露list实例,这样不管是不是同包、是不是子类,只要拿到同一个ArrayListClass实例就能拿到对应的同一个list:
首先修改ArrayListClass:
public class ArrayListClass { protected ArrayList<SomeClass> someClass = new ArrayList<>(); // 新增公开方法返回同一个list引用 public ArrayList<SomeClass> getSharedList() { return someClass; } }
然后Another类通过构造方法传入同一个ArrayListClass实例,拿到list引用存为成员即可:
public class Another { private final ArrayList<SomeClass> sharedList; // 构造时传入持有list的ArrayListClass实例 public Another(ArrayListClass listHolder) { this.sharedList = listHolder.getSharedList(); } private void method1() { sharedList.add(new SomeClass()); } private void method2() { sharedList.remove(0); } public void method3() { System.out.println(sharedList.size()); } }
使用时只要保证传入所有Another实例的是同一个ArrayListClass对象,就能实现跨实例、跨方法共用同一个list:
public class Main { public static void main(String[] args) { // 全局唯一的list持有对象 ArrayListClass sharedHolder = new ArrayListClass(); Another a1 = new Another(sharedHolder); Another a2 = new Another(sharedHolder); // a1、a2操作的都是同一个list } }
- 不要在每个方法里单独
new ArrayListClass(),每次new都会生成新的对象,对应的someClass也是全新的ArrayList实例,无法共用。 - 如果不同包下Another既不是ArrayListClass的子类,ArrayListClass也没有提供暴露list的可访问方法,是无法直接访问protected修饰的someClass的,这是Java访问权限控制的硬性规则。
内容的提问来源于stack exchange,提问作者worker2

