Почему подкласс в другом пакете не может получить доступ к защищенному методу?
У меня есть два класса в двух разных пакетах:
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();
?
8 ответов
Защищенные методы могут быть доступны только через наследование в подклассах вне пакета. И, следовательно, второй подходtryMeProtected();
работает.
Код ниже не будет компилироваться, потому что мы не вызываем унаследованную версию защищенного метода.
Class1 c = new Class1();
c.tryMeProtected(); // ERROR: tryMeProtected() has protected access in Class1
Перейдите по этой ссылке для более подробного объяснения.
Я полагаю, вы неправильно понимаете разницу между 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
}
}
Вы используете два разных пакета и обращаетесь к своим родительским атрибутам не посредством прямого наследования, а через промежуточный родительский экземпляр, объявленный в дочернем классе (аналогично составу). => это не так 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
}
}
Действительно, это особенность protected
Ключевое слово часто неправильно понимают.
Прежде всего, вам нужно понять две вещи:
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.
Это может быть достигнуто двумя способами
1. Либо путем создания объекта класса Child, а затем доступа к защищенному методу класса Parent.
ПАКЕТ 1
public class Class1 {
protected void m1() {
System.out.println("m1 called");
}
}
package2
public class Class2 extends Class1 {
public static void main(String[] args) {
Class2 class2 = new Class2();
class2.m1();
}
}
2. Или путем прямого вызова метода из класса Child
eg tryMeProtected();
Согласно методам определения модификатора Защищенного доступа Java, которые объявлены защищенными в суперклассе, могут быть доступны только подклассы в другом пакете или любой класс в пакете класса защищенных членов.
Вы не можете получить доступ к защищенному методу, создав объект класса. Поэтому для доступа к защищенному методу вы должны расширить суперкласс (это объясняет, что ваш второй вызов правильный)
Вы попробуйте так: -
public class Class2 extends Class1 {
doNow() {
Class2 c = new Class2();
c.tryMeProtected(); // No error
tryMeProtected(); // error
}
}
Модификатор protected - 1.Package Private 2. Может быть виден подклассами из других пакетов. теперь ключевое различие между:
MyClass1 c = new MyClass1();
c.tryMeProtected();
а также
tryMyProtected();
заключается в том, что используется ссылка MyClass1, а не наследование. MyClass1 находится в другом пакете, и этот код не наследуется от MyClass1.