Почему подкласс в другом пакете не может получить доступ к защищенному методу?

У меня есть два класса в двух разных пакетах:

package package1;

public class Class1 {
    public void tryMePublic() {
    }

    protected void tryMeProtected() {
    }
}


package package2;

import package1.Class1;

public class Class2 extends Class1 {
    doNow() {
        Class1 c = new Class1();
        c.tryMeProtected(); // ERROR: tryMeProtected() has protected access in Class1
        tryMeProtected();  // No error
    }    
}

Я могу понять, почему при вызове tryMeProtected() нет ошибки, поскольку Class2 видит этот метод как наследуемый от Class1.

Но почему объект Class2 не может получить доступ к этому методу для объекта Class1 с помощью c.tryMeProtected();?


person user2986848    schedule 13.11.2013    source источник
comment
Этот код не вызывает эту ошибку. Метода tryMeProtected() вообще не существует.   -  person user207421    schedule 13.11.2013
comment
Вы тестировали это с точным кодом, который вы разместили? если да, это не может работать, как сказал EJP, у вас есть два разных имени: tryMePublic и tryMeProtected   -  person CloudyMarble    schedule 13.11.2013


Ответы (7)


Защищенные методы могут быть доступны только через наследование в подклассах вне пакета. И, следовательно, второй подход tryMeProtected(); работает.

Код ниже не скомпилируется, потому что мы не вызываем унаследованную версию защищенного метода.

 Class1 c = new Class1();
 c.tryMeProtected(); // ERROR: tryMeProtected() has protected access in Class1

Перейдите по этой ссылке stackoverflow. для большего объяснения.

person Ankur Shanbhag    schedule 13.11.2013
comment
снаружи или в той же упаковке (оба конечно), не только снаружи - person Mik378; 13.11.2013
comment
В том же пакете они доступны через отдельный экземпляр, поскольку он имеет ту же видимость, что и по умолчанию в java (за исключением подклассов, которые могут наследоваться даже за пределами пакета). - person Ankur Shanbhag; 13.11.2013
comment
Да, согласен, я бы предпочел фразу типа: Наследование protected методов имеет смысл только с разными пакетами. ;) - person Mik378; 13.11.2013
comment
@ Mik378: Да, верно. Я изменил заявление в посте. Спасибо, что указали на это. :-) - person Ankur Shanbhag; 13.11.2013

Я полагаю, вы неправильно понимаете разницу между видимостью package и protected.

package package1;

public class MyClass1 {
    public void tryMePublic() { System.out.println("I'm public"); }
    protected void tryMeProtected() { System.out.println("I'm protected"); }
    void tryMePackage() { System.out.println("I'm package"); }
}
  • tryMePublic будет доступен, где бы вы ни находились.
  • tryMeProtected будет доступен каждому подклассу И каждому классу в одном пакете.
  • tryMePackage будет доступно для каждого класса в одном пакете (недоступно в дочернем классе, если они находятся в другом пакете)

Детский класс в одном пакете

package package1;

public class Class2 extends MyClass1 {
    public void doNow() {
        tryMePublic(); // OK
        tryMeProtected(); // OK
        tryMePackage(); // OK
    }    
}

Детский класс в другом пакете

package package2;

import package1.MyClass1;

public class Class3 extends MyClass1 {
    public void doNow() {
        MyClass1 c = new MyClass1();
        c.tryMeProtected() // ERROR, because only public methods are allowed to be called on class instance, whereever you are
        tryMePublic(); // OK
        tryMeProtected(); // OK
        tryMePackage(); // ERROR
    }    
}
person Anthony Raymond    schedule 28.04.2016

Вы используете два разных пакета и получаете доступ к своим родительским атрибутам не путем прямого наследования, а через промежуточный родительский экземпляр, объявленный в дочернем классе (аналогично композиции). => protected работает не так.

Только прямое наследование позволяет получить доступ к защищенным родительским атрибутам.

Таким образом, вы можете сделать это:

public class Class2 extends Class1 {
    doNow() {
        tryMeProtected();  // No error since direct inheritance 
    }    
}

но никогда это:

public class Class2 extends Class1 {
    doNow() {
        Class1 c = new Class1();
        c.tryMeProtected(); // this is not a direct inheritance! since `c`, although a parent one is an intermediate instance created in the child instance. => bad
    }    
}

Действительно, это особенность protectedkeyword, которую часто неправильно понимают.

person Mik378    schedule 13.11.2013
comment
@CloudyMarble Конечно, но суть концепции наследования с защищенным ключевым словом заключается в разных пакетах. В противном случае было бы достаточно области пакетов по умолчанию. Конечно: кто может больше, тот может меньше - person Mik378; 13.11.2013

Прежде всего, вам нужно понять две вещи:

1) Доступ к protected функциям-членам класса «X» в пакете «Y» может получить подкласс, т. е. класс, который его расширяет (даже если подкласс находится в пакете, отличном от «Y»). Поэтому,

tryMeProtected(); // Showed no error because this was called by class 2 that is the subclass.

2) Функция-член protected класса «X» в пакете «Y» не может быть доступна сама по себе, если она находится в других пакетах.

[Простая аналогия: птица, яйца которой хранятся в гнезде 1, перелетела в гнездо 2. Из гнезда 2 она не может получить доступ к своему яйцу, хранящемуся в гнезде 1.] Точно так же класс не может получить доступ к своей функции-члену (если только public объявлен.), если он находится в другом пакете.

Поэтому :

c.tryMeProtected();  // Showed error because this was called by class 1 reference.
                     //  You can also think of it as class 1 cannot inherit itself.
person Dewansh Nigam    schedule 06.08.2018

В соответствии с методами определения модификатора защищенного доступа Java, которые объявлены защищенными в суперклассе, могут быть доступны только подклассы в другом пакете или любой класс в пакете класса защищенных членов.

вы не можете получить доступ к защищенному методу, создав объект класса. Итак, для доступа к защищенному методу вам необходимо расширить суперкласс (это объясняет, что ваш второй вызов правильный)

person Tushar D    schedule 13.11.2013

Это может быть достигнуто двумя способами

<сильный>1. Либо создав объект класса Child, а затем обратившись к защищенному методу класса Parent.

ПАКЕТ 1

public class Class1 {
    protected void m1() {
        System.out.println("m1 called");
    }
}

ПАКЕТ2

public class Class2 extends Class1 {

    public static void main(String[] args) {
        Class2 class2 = new Class2();
        class2.m1();
    }
}

<сильный>2. Или напрямую вызвав метод из класса Child

eg tryMeProtected();

person Satyam    schedule 04.02.2014

защищенный модификатор 1.Package Private 2.может быть замечен подклассами из других пакетов. теперь ключевое различие между:

MyClass1 c = new MyClass1();
    c.tryMeProtected();

а также

tryMyProtected(); 

заключается в том, что используется ссылка MyClass1, а не наследование. MyClass1 находится в другом пакете, и этот код не наследуется от MyClass1.

person Nora alshareef    schedule 29.03.2020