私有类数组的长度无法访问

afz*_*lex 14 java arrays

请考虑以下代码:

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中如果我们无法访问任何东西,甚至无法知道私有类数组的长度那么创建私有类数组有什么用.

Rea*_*tic 5

这样做的原因是 JLS 中两个语句的组合:

  1. 第 6.6.1 项确定可访问性:

    数组类型可访问当且仅当其元素类型可访问。

    这意味着如果T是私有的,T[]也被认为是私有的。

  2. 条款 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它本身是私有的,您无法访问其成员,无论是公共的还是私有的。

请注意,尽管它是公开的iB但我们无法访问。如果我们使用:

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 []所以你可以通过它。
  • 无法访问可访问超类型中不存在的私有类型的公共成员。