概述
protected
方法的调用是否合法(编译是否通过),关键是要看 调用者所在的类与被调用的 protected
方法所在的类是否在相同的包下,若相同,则合法;否则,不合法。
- 在子类内部,任何情况下都可以访问父类的
protected
方法
栗子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Father1 { protected void f() {} }
public class Son1 extends Father1 {}
public class Son2 extends Father1 {}
public class Test1 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f();
Son2 son2 = new Son2(); son2.f(); } }
public class Test2 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f();
Son2 son2 = new Son2(); son2.f(); } }
|
更有趣的栗子
### $\text{栗}_1$
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MyObject1_2 {}
public class Test1_2 { public static void main(String[] args) { MyObject1_2 myObject1_2 = new MyObject1_2(); myObject12.clone(); Test1_2 test1_2 = new Test1_2(); test1_2.clone(); } }
|
这里 `myObject1_2.clone` 是继承自 `Object` 的 `protected` 方法,虽然 `Test1_2` 也是 `Object` 的子类,但是 `Test1_2` 和 `MyObject1_2` 并不存在直接的继承关系,并且由于 `Object` 和 `Test1_2` 不在同一个包中,因此编译不通过。
而由于 `Test1_2` 继承自 `Object`,因此可在 `Test1_2` 内部任意调用从 `Object` 继承来的 `protected` 方法。
### $\text{栗}_2$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class MyObject1_3 { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
class MyObject2_3 extends MyObject1_3 {}
public class Test2_3 extends MyObject1_3 { public static void main(String[] args) throws CloneNotSupportedException { MyObject1_3 myObject1_3 = new MyObject1_3(); myObject1_3.clone(); MyObject2_3 myObject2_3 = new MyObject2_3(); myObject2_3.clone();
Test2_3 test2_3 = new Test2_3(); test2_3.clone(); } }
|
和 ***[$\text{栗}_1$](#example_1)*** 中不同,`Test2_3` 继承自 `MyObject1_3`,
**因此 `main` 中调用的 `clone` 都可追溯到 `MyObject1_3` 所在的包 `p1`**,以此为前提,很容易分析:
1. `myObject1_3.clone()`:
> 因为 `Test2_3` 在包 `p2` 下,和 `clone` 所在的包不同,因此编译不通过。
2. `myObject2_3.clone()`:
> 虽然 `MyObject2_3` 和 `Test2_3` 在同一个包下,但由 **[前提](#tmp_asd1)** 很容易分析出编译不通过的原因。
3. `test2_3.clone()`:
> 在 `Test2_3` 内部调用继承来的 `protected` 方法都是合法的。
### $\text{栗}_3$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class MyObject1_3 { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
public class Test1_3 extends MyObject1_3 { public static void main(String[] args) throws CloneNotSupportedException { MyObject1_3 myObject1_3 = new MyObject1_3(); myObject1_3.clone(); Test1_3 test1_3 = new Test2_3(); test1_3.clone(); } }
|
与 ***[$\text{栗}_2$](#example_2)*** 中不同,`MyObject1_3` 和 `Test1_3` 在一个包下,所以可以调用 `MyObject1_3` 的 `protected` 方法。
### $\text{栗}_4$
1 2 3 4 5 6 7 8 9 10
| public class MyObject1_4 extends Test2_4 {}
public class Test2_4 { public static void main(String[] args) throws CloneNotSupportedException { MyObject1_4 myObject1_4 = new MyObject1_4(); myObject1_4.clone(); } }
|
因为 `MyObject1_4` 的 `clone` 继承自 `Test2_4`,所以 `clone` 方法和 `Test2_4` 在相同的包下,因此编译通过。(注意与 ***[$\text{栗}_1$](#example_1)*** 对比)
### $\text{栗}_5$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MyObject1_5 extends Test2_5 { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
public class Test2_5 { public static void main(String[] args) { MyObject1_5 myObject1_5 = new MyObject1_5(); myObject1_5.clone(); } }
|
与 ***[$\text{栗}_4$](#example_4)*** 不同,`MyObject1_5` 覆盖了父类的 `clone` 方法,因此在调用 `MyObject1_5` 的 `clone` 方法时,实际上是被调用的方法所在的包为 `p1`,而 `Test2_5` 所在的包为 `p2`,因此编译不通过。
Hint
参考链接