简体   繁体   English

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

[英]length of array of private class is not accessible

Please consider the following code : 请考虑以下代码:

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
    }
}

As I written in code. 正如我在代码中写的那样。 a.arr.length; is giving error. 给出错误。

I actually understand why it is happening. 我真的明白为什么会这样。 It is because sub class B is private. 这是因为子类B是私有的。 But still why it is happening. 但仍然为什么会这样。 In class A, property arr was accessible, but why not it's length. 在A类中,属性arr是可访问的,但为什么不是它的长度。 Is there any explanation for this in jls or anywhere. 在jls或任何地方有没有任何解释。

I just want a clear explanation for this behaviour. 我只想对这种行为做出明确的解释。 I know private things cannot be accessed outside of its class. 我知道私人事物不能在同类之外访问。 But a public array could be. 但公共阵列可能是。 No matter of what type it is. 无论是什么类型。 And if anything is accessible outside, then its public properties should also be accessed. 如果外面有任何东西可以访问,那么也应该访问它的公共属性。 But here it is not happening. 但这里没有发生。

Edit : I found that in C# it is not even possible to create an array of private class. 编辑:我发现在C#中甚至不可能创建一个私有类数组。 In java if we cannot access anything, and cannot even know the length of the array of private class then what is the use of creating an array of private class. 在java中如果我们无法访问任何东西,甚至无法知道私有类数组的长度那么创建私有类数组有什么用。

The reason for this is a combination of two statements in the JLS: 原因是JLS中两个语句的组合:

  1. Item 6.6.1 Determining accessibility: 项目6.6.1确定可访问性:

    An array type is accessible if and only if its element type is accessible. 当且仅当其元素类型可访问时,才能访问数组类型。

    This means that if T is private, T[] is also considered private. 这意味着如果T是私有的, T[]也被认为是私有的。

  2. Item 10.7 Array members: 项目10.7阵列成员:

    The public final field length , which contains the number of components of the array. public final字段length ,包含数组的组件数。 length may be positive or zero. 长度可以是正数或零。

Remember that accessibility is determined at compile-time based on the type of reference you have, not on the type of the actual object! 请记住,可访问性是在编译时根据您具有的引用类型而不是实际对象的类型确定的!

Now, let's go into a little more elaborate example to demonstrate what this means. 现在,让我们进入一个更详细的例子来证明这意味着什么。 I added a toString() and a constructor to B . 我向B添加了一个toString()和一个构造函数。

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 + ")";
        }

    }
}

Now, in class C, we use: 现在,在C类中,我们使用:

A a = new A();
Object plain = a.plain;
String s = plain.toString();

This is legal, because a.plain is a visible field. 这是合法的,因为a.plain是一个可见字段。 s will contain Hidden class B(99) . s将包含Hidden class B(99) But if you try: 但如果你尝试:

String s = a.plain.toString(); // Compile error

This will not be allowed, because althogh toString() in B is public, B itself is private, you have no access to its members, whether public or private. 这是不允许的,因为B althogh toString()是公共的, B本身是私有的,你无法访问其成员,无论是公共还是私有。

Note that we cannot access i in B despite its being public. 请注意,尽管B公开,但我们无法访问B i If we use: 如果我们使用:

plain.i

Then since i is not a member of Object , you get a compile error. 然后因为i不是Object的成员,所以会出现编译错误。 And if we use: 如果我们使用:

a.plain.i

Then since a.plain is private, you can't access its members, as we already tried. 然后,由于a.plain是私有的,因此我们已经尝试过,您无法访问其成员。

So now we go and look at the issue of arrays. 所以现在我们来看看数组的问题。 Suppose we write: 假设我们写道:

Object[] objArr = a.arr;
int len = objArr.length;

This is legal, despite the fact that objArr is internally AB[] . 尽管objArr是内部AB[]objArr是合法的。 We have a reference to Object[] , Object is public and so is Object[] . 我们引用了Object[]Object是public,因此是Object[] But: 但:

int len = a.arr.length;

Gives you a compile error exactly as we got for a.plain.toString() . 完全按照我们为a.plain.toString()获得的编译错误。 Although length is public in itself, you are accessing it through a reference to AB[] . 尽管length本身是公共的,但您通过引用AB[]来访问它。 AB[] is not accessible because AB is not accessible. AB[]无法访问,因为AB无法访问。 And therefore, because length is its member, you cannot access it. 因此,因为length是其成员,所以您无法访问它。 You simply cannot access any member of a reference type that is not visible to you, by the first rule above. 您无法通过上面的第一条规则访问您不可见的任何引用类型的成员。

It is interesting to note that the following is legal: 有趣的是,以下合法的:

Object firstItem = a.arr[0];

We can use the expression a.arr[0] because it is not considered an attempt to access a member of the array. 我们可以使用表达式a.arr[0]因为它不被视为访问数组成员的尝试。 The elements of the array are not considered to be members in it. 数组的元素不被视为其中的成员。 a.arr[0] is simply an expression on an array reference that resolves to type AB . a.arr[0]只是解析为AB类型的数组引用的表达式。 There is no problem with such an expression as long as we don't try to access members of the item. 只要我们不尝试访问项目的成员,这样的表达就没有问题。

firstItem.toString() // Good
a.arr[0].toString()  // Bad

Summary 摘要

  • It's OK to get hold to a reference to a private type, provided you cast it to some public supertype. 只要将其转换为某种公共超类型,就可以保持对私有类型的引用。
  • It's OK to get a specific item in an array of a private type. 在私有类型的数组中获取特定项是可以的。 Indexing the array is not considered "accessing a member", it's just an expression on a reference that gives you a reference to its member type. 索引数组不被视为“访问成员”,它只是引用上的一个表达式,它为您提供对其成员类型的引用。 Which you'll need to cast to something public in order to use. 您需要将其投射到公共场所才能使用。
  • It's not OK to try accessing a member with a given reference to a private type, even if the member is public. 尝试访问具有给定私有类型引用的成员是不正常的,即使该成员是公共的。 This includes the length of an array. 这包括数组的length
  • It's OK to access that public member through a cast to a supertype if it's available in that supertype. 如果在超类型中可用,则可以通过强制转换访问该公共成员。 length is available in Object [] so you can get it through that. lengthObject []可用,因此您可以通过它。
  • It's not possible to access a public member of a private type that doesn't exist in an accessible supertype. 无法访问在可访问的超类型中不存在的私有类型的公共成员。

Do this: 做这个:

 class A {
    B[] arr = new B[10];

    public int getArrayLength()
    {
        return arr.length;
    }
    private class B {}
}


class C {
    void fun(){
        A a = new A();
        Object arr = a.arr;
        //Object isn't type safe
        //Object len = a.getArrayLength();
        int len = a.getArrayLength();
    }
}

According to JavaDocs 根据JavaDocs

At the member level, you can also use the public modifier or no modifier (package-private) just as with top-level classes, and with the same meaning. 在成员级别,您也可以使用public修饰符或no修饰符(package-private),就像使用顶级类一样,并且具有相同的含义。 For members, there are two additional access modifiers: private and protected. 对于成员,还有两个额外的访问修饰符:private和protected。 The private modifier specifies that the member can only be accessed in its own class. private修饰符指定只能在自己的类中访问该成员。 The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package. protected修饰符指定只能在其自己的包中访问该成员(与package-private一样),此外,还可以在另一个包中通过其类的子类访问该成员。

Knows that the question is about accessing the length field. 知道问题是关于访问length字段。 But, it was interesting for me to find that the length can be determined by enhanced-for-loop, not by making changes to access privileges or using reflection: 但是,有趣的是我发现length可以通过增强循环来确定,​​而不是通过更改访问权限或使用反射来确定:

int length = 0;
for(Object o : a.arr) {
    length++;
}

Few interesting statements about arrays were: 关于数组的几个有趣的陈述是:

Arrays 数组

In the Java programming language, arrays are objects (§4.3.1), are dynamically created, and may be assigned to variables of type Object (§4.3.2). 在Java编程语言中,数组是对象(§4.3.1),是动态创建的,可以分配给Object类型的变量(§4.3.2)。 All methods of class Object may be invoked on an array. 可以在数组上调用Object类的所有方法。

Array Types 数组类型

An array's length is not part of its type. 数组的长度不是其类型的一部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM