请考虑以下代码:
class A {
B[] arr = new B[10];
private class B {}
}
class C {
void fun(){
A a = new A();
Object arr = a.arr;
Object len = a.arr.length; // !! ERROR
}
}
Run Code Online (Sandbox Code Playgroud)
正如我在代码中写的那样.a.arr.length;给出错误.
我真的明白为什么会这样.这是因为子类B是私有的.但仍然为什么会这样.在A类中,属性arr是可访问的,但为什么不是它的长度.在jls或任何地方有没有任何解释.
我只想对这种行为做出明确的解释.我知道私人事物不能在同类之外访问.但公共阵列可能是.无论是什么类型.如果外面有任何东西可以访问,那么也应该访问它的公共属性.但这里没有发生.
编辑:我发现在C#中甚至不可能创建一个私有类数组.在java中如果我们无法访问任何东西,甚至无法知道私有类数组的长度那么创建私有类数组有什么用.
这样做的原因是 JLS 中两个语句的组合:
第 6.6.1 项确定可访问性:
数组类型可访问当且仅当其元素类型可访问。
这意味着如果T是私有的,T[]也被认为是私有的。
条款 10.7数组成员:
的
public final字段length,其中包含所述阵列的部件的数量。长度可以是正数或零。
请记住,可访问性是在编译时根据您拥有的引用类型确定的,而不是实际对象的类型!
现在,让我们进入一个更详细的例子来演示这意味着什么。我添加了一个toString()和一个构造函数到B.
class A {
B[] arr = { new B(1), new B(2), new B(3), new B(4) };
B plain = new B(99);
private class B {
public int i;
B(int i) {
this.i = i;
}
@Override
public String toString() {
return "Hidden class B(" + i + ")";
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在 C 类中,我们使用:
A a = new A();
Object plain = a.plain;
String s = plain.toString();
Run Code Online (Sandbox Code Playgroud)
这是合法的,因为a.plain是一个可见字段。s将包含Hidden class B(99). 但如果你尝试:
String s = a.plain.toString(); // Compile error
Run Code Online (Sandbox Code Playgroud)
这是不允许的,因为 althogh toString()inB是公共的,B它本身是私有的,您无法访问其成员,无论是公共的还是私有的。
请注意,尽管它是公开的i,B但我们无法访问。如果我们使用:
plain.i
Run Code Online (Sandbox Code Playgroud)
然后由于i不是 的成员Object,您会收到编译错误。如果我们使用:
a.plain.i
Run Code Online (Sandbox Code Playgroud)
然后因为a.plain是私有的,你不能访问它的成员,正如我们已经尝试过的。
所以现在我们去看看数组的问题。假设我们写:
Object[] objArr = a.arr;
int len = objArr.length;
Run Code Online (Sandbox Code Playgroud)
这是合法的,尽管这objArr是内部的A.B[]。我们有一个引用Object[],Object是公开的,也是Object[]。但:
int len = a.arr.length;
Run Code Online (Sandbox Code Playgroud)
给你一个编译错误,就像我们得到的一样a.plain.toString()。虽然length本身是公开的,但您是通过对A.B[]. A.B[]不可访问,因为A.B不可访问。因此,因为length是它的成员,所以你不能访问它。根据上面的第一条规则,您根本无法访问对您不可见的引用类型的任何成员。
有趣的是,以下是合法的:
Object firstItem = a.arr[0];
Run Code Online (Sandbox Code Playgroud)
我们可以使用该表达式,a.arr[0]因为它不被视为试图访问数组成员。数组的元素不被视为其中的成员。a.arr[0]只是解析为 type 的数组引用上的表达式A.B。只要我们不尝试访问项目的成员,这样的表达式就没有问题。
firstItem.toString() // Good
a.arr[0].toString() // Bad
Run Code Online (Sandbox Code Playgroud)
概括
length数组的 。length是可用的,Object []所以你可以通过它。