Ответ 1
Причиной этого является комбинация двух операторов в 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()
in B
является общедоступным, сам B
является закрытым, у вас нет доступа к его членам, будь то public или private.
Обратите внимание, что мы не можем получить доступ к 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
Резюме
- В порядке, чтобы получить привязку к типу private, при условии, что вы применили его к некоторому публичному супертипу.
- Это нормально, чтобы получить конкретный элемент в массиве частного типа. Индексирование массива не считается "доступом к члену", это просто выражение в ссылке, которое дает ссылку на его тип члена. Что вам нужно будет использовать для чего-то публичного для использования.
- Не удается попробовать получить доступ к члену с заданной ссылкой на закрытый тип, даже если этот элемент является общедоступным. Это включает в себя
length
массива. - Это нормально, чтобы получить доступ к этому публичному пользователю с помощью приведения к супертипу, если он доступен в этом супертипе.
length
доступен вObject []
, поэтому вы можете получить это через. - Невозможно получить доступ к публичному члену частного типа, который не существует в доступном супертипе.