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

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

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.

Другие вопросы по тегам