其原因是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 + ")";
}
}
}
现在,在类C中,我们使用:
A a = new A();
Object plain = a.plain;
String s = plain.toString();
这是合法的,因为它是一个可见的字段。 将包含 .但如果你尝试:a.plain
s
Hidden class B(99)
String s = a.plain.toString(); // Compile error
这是不允许的,因为althogh是公共的,本身是私有的,你无法访问它的成员,无论是公共的还是私人的。toString()
B
B
请注意,尽管它是公开的,但我们仍然无法访问。如果我们使用:i
B
plain.i
然后由于 不是 的成员,你会得到一个编译错误。如果我们使用:i
Object
a.plain.i
然后,由于是私有的,因此您无法访问其成员,正如我们已经尝试过的那样。a.plain
所以现在我们来看看数组的问题。假设我们写:
Object[] objArr = a.arr;
int len = objArr.length;
这是合法的,尽管事实是内部的 。我们有一个引用,是公开的,也是。但:objArr
A.B[]
Object[]
Object
Object[]
int len = a.arr.length;
为您提供的编译错误与 我们对 .尽管它本身是公共的,但您正在通过对 的引用来访问它。 不可访问,因为 不可访问。因此,因为它是其成员,因此您无法访问它。根据上面的第一条规则,您根本无法访问对您不可见的引用类型的任何成员。a.plain.toString()
length
A.B[]
A.B[]
A.B
length
有趣的是,以下是合法的:
Object firstItem = a.arr[0];
我们可以使用该表达式,因为它不被视为尝试访问数组的成员。数组的元素不被视为其中的成员。 只是解析为类型 的数组引用上的表达式。只要我们不尝试访问项目的成员,这样的表达式就没有问题。a.arr[0]
a.arr[0]
A.B
firstItem.toString() // Good
a.arr[0].toString() // Bad
总结
- 可以保留对私有类型的引用,前提是将其转换为某个公共超类型。
- 可以在私有类型的数组中获取特定项。为数组编制索引不被视为“访问成员”,它只是引用上的一个表达式,它为您提供了对其成员类型的引用。您需要将其投射到公共内容才能使用。
- 尝试访问具有对私有类型的给定引用的成员是不允许的,即使该成员是公共的。这包括数组的 。
length
- 可以通过强制转换为超类型来访问该公共成员(如果它在该超类型中可用)。 是可用的,所以你可以得到它通过它。
length
Object []
- 无法访问在可访问超类型中不存在的私有类型的公共成员。