2015-09-16 2 views
11

Пожалуйста, обратите внимание на следующий код:длина массива частного класса не доступен

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 является закрытым. Но все же, почему это происходит. В классе А свойство arr было доступно, но почему бы и нет его длины. Есть ли объяснение этому в jls или где угодно.

Я просто хочу дать четкое объяснение этому поведению. Я знаю, что личные вещи не могут быть доступны за пределами своего класса. Но публичный массив может быть. Независимо от того, какой он тип. И если что-либо доступно снаружи, необходимо также получить доступ к его публичным свойствам. Но здесь этого не происходит.

Редактировать: Я нашел, что в C# даже невозможно создать массив частного класса. В java, если мы не можем получить доступ к чему-либо, и даже не можем знать длину массива частного класса, тогда используется создание массива частного класса.

+2

Личные данные могут быть доступны только через общедоступный метод того же класса. 'arr', поэтому он отображается внутри' A', но 'B' является закрытым, поэтому нет. удалить private из 'B', он не будет показывать никаких ошибок. – Rustam

+0

Любопытно, что вы действительно можете использовать выражение 'a.arr [0]'. – RealSkeptic

+0

Что касается вашего редактирования, существует множество применений для массива частного класса. Вы можете использовать его для внутренних целей охватывающего класса. Или вы можете отображать в нем элементы как возвращаемые значения и т. Д. – RealSkeptic

ответ

2

Причиной этого является сочетание двух утверждений в JLS:

  1. Item 6.6.1 Определение доступности:

    Тип массива является доступным, если и только если его тип элемента доступны.

    Это означает, что если T является закрытым, T[] также считается приватным.

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

    } 
} 

Теперь, в классе С, мы используем:

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. Нет никаких проблем с таким выражением, пока мы не пытаемся получить доступ к элементам элемента.

Резюме

  • Это нормально, чтобы держать на обращение частного типа, если вы бросили его в какой-то общественный надтип.
  • Это нормально, чтобы получить конкретный элемент в массиве частного типа. Индексирование массива не считается «доступом к члену», это просто выражение в ссылке, которое дает ссылку на его тип члена. Что вам нужно будет сделать для чего-то публичного для использования.
  • Нельзя попробовать получить доступ к члену с заданной ссылкой на закрытый тип, даже если член является общедоступным. Это включает в себя length массива.
  • Это нормально, чтобы получить доступ к этому публичному пользователю с помощью приведения в супертип, если он доступен в этом супертипе. length можно приобрести в Object [], чтобы вы могли это получить.
  • Доступ к публичному члену частного типа, который не существует в доступном супертипе, недоступен.
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

На уровне членов, вы можете также использовать общественный модификатор или нет модификатора (пакет-частное) только как с классами верхнего уровня , и с тем же значением. Для участников есть два дополнительных модификатора доступа: частный и защищенный. Частный модификатор указывает, что к члену можно получить доступ только в своем классе. Защищенный модификатор указывает, что к члену можно получить доступ только в своем собственном пакете (как и в пакете private) и, кроме того, подклассе его класса в другом пакете.

+1

Сообщение не проблема. Я не ищу решения. Но разложение. То, что я хотел сделать, можно было бы сделать разными способами. Но вопрос - это поведение кода, который я представил. – afzalex

+0

в ссылке на JavaDocs объясняется очень хорошо, почему ваш частный массив не виден снаружи, и если вы его не видите, то и его методы не являются –

+0

Ваша цитата не из JavaDocs, это из учебников Java. И это просто общее описание модификаторов доступа, это не объясняет, почему длина массива считается членом его класса элементов. – RealSkeptic

1

Знает, что речь идет о доступе к полю length. Но, это было интересно для меня, чтобы найти, что length может определяться повышенной для цикла, а не путем внесения изменений прав доступа или с помощью отражения:

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

Несколько интересных заявлений о массивах были:

Arrays

в языке программирования Java, массивы являются объектами (§4.3.1), являются динамически создаваемые и могут быть отнесены к переменным типа Object (§4.3.2). Все методы класса Object могут быть вызваны в массиве.

Array Types

Длина массива не является частью его типа.

Смежные вопросы