2010-08-22 2 views
13

Я хотел бы понять, что происходит в примере ниже (где доступ к защищенному члену осуществляется извне пакета через подкласс).Java: защищенный доступ через пакеты

Я знаю, что для классов вне пакета подкласс может видеть защищенный элемент только через наследование.

Есть две упаковки: package1 и package2.

  1. package1: ProtectedClass.java

    package org.test.package1; 
    
    public class ProtectedClass { 
    
        protected void foo() { 
         System.out.println("foo"); 
        } 
    } 
    
  2. package2: ExtendsprotectedClass.java

    package org.test.package2; 
    
    import org.test.package1.ProtectedClass; 
    
    public class ExtendsprotectedClass extends ProtectedClass { 
    
        public void boo() { 
         foo(); // This works, 
           // since protected method is visible through inheritance 
        } 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // Why is this working? 
            // Since it is accessed through a reference, 
            // foo() should not be visible, right? 
        } 
    } 
    
  3. package2: UsesExtendedClass.java

    package org.test.package2; 
    
    public class UsesExtendedClass { 
    
        public static void main(String[] args) { 
         ExtendsprotectedClass epc = new ExtendsprotectedClass(); 
         epc.foo(); // CompilationError: 
            // The method foo() from the type ProtectedClass 
            // is not visible 
        } 
    } 
    

Следует понимать, что метод boo() в ExtendsprotectedClass может получить доступ к foo(), так как защищенные члены могут быть доступны только через наследование.

Мой вопрос, почему метод foo() работает хорошо, когда доступ через ссылку в main() методы ExtendsprotectedClass но не будет работать при доступе через epc ссылки в UsesExtendedClass?

ответ

12

Код в пределах ExtendsprotectedClass класс разрешен для доступа к защищенным элементам ProtectedClass по ссылке ExtendsprotectedClass. Из JLS section 6.6.2:

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

и

Пусть C класс, в котором объявлен защищенный член м. Доступ разрешается только в пределах тела подкласса S С. Кроме того, если идентификатор обозначает поле экземпляра или метод экземпляра, то:

  • Если доступ осуществляется с помощью квалифицированного имени Q.Id, где Q является ExpressionName, то доступ разрешен, если и только если тип выражения Q представляет S или подкласс S. [...]

UsesExtendedClass не ответствено для осуществления ExtendsprotectedClass, поэтому окончательный вызов терпит неудачу.

EDIT: Причина в том, что доступ protected предназначен для того, чтобы помочь подклассам реализовать необходимую им функциональность, предоставляя больше доступа к внутренним элементам суперкласса, чем обычно.Если бы это было доступно для всего кода, это было бы довольно близко к тому, чтобы сделать этот метод общедоступным. В принципе, подклассам доверяют не нарушать инкапсуляцию; они получают больше возможностей внутри объектов своего типа. Открытый API не должен раскрывать эти данные, но защищенный API может только для того, чтобы предоставить подклассам больше возможностей.

+0

@Jon Спасибо. Я понимаю, что члены класса подкласса могут получить доступ к защищенным членам (как указано в методе 'boo()'). Но было любопытно узнать, почему ему разрешено обращаться к защищенному члену через ссылку подкласса ** ТОЛЬКО ** в методах подкласса? любое обоснование этого? – JWhiz

+0

@JWhiz: Редактирование ... –

+1

2) Работает потому, что, поскольку к защищенному методу обращается указатель на свой класс. Это должно завершиться неудачно:
public static void ExtendsprotectedClass.main (String [] args) { ProtectedClass epc = new ExtendsprotectedClass(); // upcast
epc.foo(); // должна быть ошибка компиляции?
} –

1

Я считаю, что вы ответили на свой вопрос; UsesExtendedClass не наследуется от ProtectedClass, а по определению - защищенные члены доступны только в классе, в котором они объявлены/определены или в классе, который наследует тот, в котором они объявлены или определены.

+2

'по определению -« защищенные »члены доступны только в классе, в котором они объявлены/определены'. Я не совсем согласен с этим, так как защищенные члены доступны из других классов внутри одного пакета без наследования. – JWhiz

2

Он работает в первом случае, потому что он вызывается из того же класса, даже к способу доступа через ссылку. Вы даже можете вызвать метод privateExtendsprotectedClass посредством ссылки в том же основном методе.

+1

Спасибо. Теперь я понимаю, почему он имеет доступ к нему через ссылку. '+ 1' для этого. Но не следует ли разрешать «частные» методы через право ссылки на объект? Разве это не нарушает саму цель сделать ее «частной»? Любая конкретная причина для этого? – JWhiz

+1

@JWhiz модификаторы доступа java работают в классе, а не на уровне экземпляра. Из-за этого частный метод является приватным для класса, а не экземпляра. Если бы частные лица работали над экземплярами, вам нужно было бы сделать больше переменных и методов общедоступными, если два экземпляра должны взаимодействовать. Это разрушит инкапсуляцию, сделав реализацию видимой вне класса. – josefx

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