请考虑以下代码:
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
}
}
正如我在代码中写的那样。 a.arr.length;
正在给出错误。
我实际上明白为什么会这样。这是因为子类B
是私有的。但仍然为什么会这样。在A类中,属性arr
是可访问的,但为什么不是它的长度。在jls或任何地方都有这方面的解释。
我只想对此行为做出明确解释。我知道私人事物不能在同类之外访问。但公共阵列可能是。无论是什么类型。如果外面有任何东西可以访问,那么也应该访问它的公共属性。但这里没有发生。
编辑:我发现在C#中甚至无法创建私有类数组。在java中如果我们无法访问任何东西,甚至无法知道私有类数组的长度那么创建私有类数组有什么用。
答案 0 :(得分:4)
原因是JLS中两个语句的组合:
Item 6.6.1确定辅助功能:
当且仅当其元素类型可访问时,才能访问数组类型。
这意味着如果T
是私有的,T[]
也会被视为私有。
Item 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
这是不允许的,因为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 []
,因此您可以完成此操作。答案 1 :(得分:3)
这样做:
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();
}
}
根据JavaDocs
在成员级别,您也可以使用public修饰符或no修饰符(package-private),就像使用顶级类一样,并且具有相同的含义。对于成员,还有两个额外的访问修饰符:private和protected。 private修饰符指定只能在自己的类中访问该成员。 protected修饰符指定只能在自己的包中访问该成员(与package-private一样),此外,还可以在另一个包中通过其类的子类访问该成员。
答案 2 :(得分:1)
知道问题是关于访问createBlockBlobFromText
字段。但是,有趣的是我发现length
可以通过增强型循环来确定,而不是通过更改访问权限或使用反射来确定:
length
关于数组的几个有趣的陈述是:
在Java编程语言中,数组是对象(§4.3.1),是 动态创建,可以分配给Object类型的变量 (§4.3.2)。可以在数组上调用Object类的所有方法。
数组的长度不属于其类型。