Многие книги, знакомящие с языком Java (включая "Thinking in Java"), дают довольно простое объяснение protected, по сути всего одно предложение:Члены, объявленные с модификатором protected, видимы текущему пакету и его подклассам. Это утверждение слишком расплывчато и часто приводит к недопониманию. На самом деле видимость protected заключается в двух моментах:

  • Члены базового класса с модификатором protected видимы внутри пакета и для подклассов;
  • Если подкласс и базовый класс находятся не в одном пакете, то в подклассе экземпляр подкласса может получать доступ к protected-методам, унаследованным от базового класса, но не может получать доступ к protected-методам экземпляра базового класса.

Мы можем глубже освоить ключевое слово protected с помощью следующих примеров, касающихся видимости protected-методов. Когда встречается вызов, связанный с protected-членом, сначала определите, откуда происходит этот protected-член и какова область его видимости, а затем можно судить, допустимо ли текущее использование. Рассмотрим следующие семь примеров:

Пример 1

package p1; public class Father1 { protected void f() {} //protected-метод родительского класса Father1 } package p1; public class Son1 extends Father1 {} package p11; public class Son11 extends Father1{} package p1; public class Test1 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f(); // Компиляция OK ----(1) son1.clone(); // Ошибка компиляции ----(2) Son11 son = new Son11(); son11.f(); // Компиляция успешна ----(3) son11.clone(); // Ошибка компиляции ----(4) } }

В приведённом выше примере сначала рассмотрим (1) и (3). Метод f() наследуется от класса Father1, и его область видимости — пакет p1 и его подклассы Son1 и Son11. Поскольку пакет класса Test1, который вызывает метод f(), также p1, компиляция проходит в (1) и (3). Теперь рассмотрим (2) и (4). Область видимости метода clone() — пакет java.lang и все его подклассы. Для операторов "son1.clone();" и "son11.clone();" методы clone() видны в классах Son1 и Son11, но не видны для Test1, поэтому компиляция завершается ошибкой в (2) и (4).

Пример 2

package p2; class MyObject2 { protected Object clone() throws CloneNotSupportedException{ return super.clone(); } } package p22; public class Test2 extends MyObject2 { public static void main(String args[]) { MyObject2 obj = new MyObject2(); obj.clone(); // Ошибка компиляции ----(1) Test2 tobj = new Test2(); tobj.clone(); // Компиляция успешна ----(2) } }

Для (1) метод clone() происходит из самого класса MyObject2, поэтому его область видимости — пакет p2 и подклассы MyObject2. Хотя Test2 является подклассом MyObject2, в Test2 нельзя получить доступ к protected-методу clone() базового класса MyObject2, поэтому компиляция завершается ошибкой. Для (2), поскольку в Test2 осуществляется доступ к clone(), унаследованному от базового класса MyObject2 его собственным экземпляром, компиляция проходит.

Пример 3

package p3; class MyObject3 extends Test3 { } package p33; public class Test3 { public static void main(String args[]) { MyObject3 obj = new MyObject3(); obj.clone(); // Компиляция OK ------(1) } }

Для (1) метод clone() происходит из класса Test3, поэтому его видимость — пакет p33, а его подкласс — MyObject3. И (1) вызывается именно в классе Test3 из пакета p33, то есть в том же пакете, поэтому компиляция проходит.

Пример 4

package p4; class MyObject4 extends Test4 { protected Object clone() throws CloneNotSupportedException { return super.clone(); } } package p44; public class Test4 { public static void main(String args[]) { MyObject4 obj = new MyObject4(); obj.clone(); // Ошибка компиляции -----(1) } }

В случае (1) метод clone() наследуется из класса MyObject4, поэтому его видимость — пакет p4 и его подклассы (здесь подклассов нет). Но класс Test4 находится в пакете p44, поэтому условие видимости не выполняется, и компиляция завершается ошибкой.

Пример 5

package p5; class MyObject5 { protected Object clone() throws CloneNotSupportedException{ return super.clone(); } } public class Test5 { public static void main(String[] args) throws CloneNotSupportedException { MyObject5 obj = new MyObject5(); obj.clone(); // Компиляция успешна ----(1) } }

В случае (1) метод clone() наследуется из класса MyObject5, поэтому его видимость — пакет p5 и его подклассы (здесь подклассов нет). Класс Test5 также находится в пакете p5, поэтому условие видимости выполняется, и компиляция проходит.

Пример 6

package p6; class MyObject6 extends Test6{} public class Test6 { public static void main(String[] args) { MyObject6 obj = new MyObject6(); obj.clone(); // Компиляция прошла успешно -------(1) } }

Для (1) метод clone() происходит из класса Test6, поэтому его видимость — package p6, а его подкласс — MyObject6. Класс Test6 также находится в пакете p6, поэтому условие видимости выполнено, и компиляция проходит.

Пример 7

package p7; class MyObject7 extends Test7 { public static void main(String[] args) { Test7 test = new Test7(); test.clone(); // Ошибка компиляции ----- (1) } } public class Test7 { }

Для (1) метод clone() происходит из класса Object, поэтому видимость этого метода clone() — package java.lang, а его подкласс — Test7. Поскольку класс MyObject7 не находится в этой области видимости, условие видимости не выполнено, и компиляция завершается ошибкой.

Источник: http://blog.csdn.net/justloveyou_/article/details/61672133