1. 前言
一句话:对同一包内的类和所有子类可见。
它的意思是可见需要满足两个条件之一:
- 调用 protected方法所在类 和 被调用protected方法所在类在相同包下。
- 调用 protected方法所在类 是 被调用protected方法所在类的子类
需要注意的点是方法所在类。比如子类未重写
下面将通过IDEA的提示来快速分辨各种情况是否可见。
2. 准备
2.1 被测试类看做父亲、儿子、侄子
父亲儿子在一个包,侄子在另一个包。
ChildOne、ChildTwo、NephewOne、NephewTwo继承Parent。
其中ChildTwo、NephewTwo重写了function(),打印语句为自己类的名字。ChildOne、NephewOne不重写方法。
如下列举两个儿子类的内容。侄子同理。
package com.base.child;
import com.base.parent.Parent;
public class ChildOne extends Parent {
}
package com.base.child;
import com.base.parent.Parent;
public class ChildTwo extends Parent {
@Override
protected void function(){
System.out.println("ChildTwo");
}
}
2.2 Test类的作用
Test在父亲、侄子、外人的包里分别调用各个类的方法验证可见性
public class Test {
public static void main(String[] args) {
ChildOne childOne = new ChildOne();
ChildTwo childTwo = new ChildTwo();
Parent childOneParent = new ChildOne();
Parent childTwoParent = new ChildTwo();
childOne.function();
childTwo.function();
childOneParent.function();
childTwoParent.function();
NephewOne nephewOne = new NephewOne();
NephewTwo nephewTwo = new NephewTwo();
Parent nephewOneParent = new NephewOne();
Parent nephewTwoParent = new NephewTwo();
nephewOne.function();
nephewTwo.function();
nephewOneParent.function();
nephewTwoParent.function();
}
}
2.3 关系
引用类型 | 实际类型 | 是否重写function | function所属类 | 所属包 | |
---|---|---|---|---|---|
childOne | ChildOne | ChildOne | 否 | Parent | 父包 |
childTwo | ChildTwo | ChildTwo | 是 | ChildTwo | 父包 |
childOneParent | Parent | ChildOne | 否 | Parent | 父包 |
childTwoParent | Parent | ChildTwo | 是 | Parent(但使用childTwo的方法) | 父包 |
nephewOneParent | Parent | NephewOne | 否 | Parent | 父包 |
nephewTwoParent | Parent | NephewTwo | 是 | Parent(但使用NephewTwo的方法) | 父包 |
nephewOne | NephewOne | NephewOne | 否 | Parent | 父包 |
nephewTwo | NephewTwo | NephewTwo | 是 | NephewTwo | 侄子包 |
childOne、childTwo、childOneParent 、childTwoParent 、nephewOneParent 、nephewTwoParent 引用类本身都在父包下。
虽然nephewTwoParent 、nephewOneParent 是侄子类创建的对象,但引用类型为父类型,因此调用nephewTwoParent.function()时调用到了父包下的方法。
nephewOne、nephewTwo类本身在侄子包下。
但是nephewOne未重写function方法,因此调用nephewOne.function()时调用到了父包下。
结论:
调用对象的protected方法时
- 如果对象的引用类型定义或重写过该方法,则function所属类和包为其引用类型的类和包。
- 如果对象的引用类型未重写过该方法,则function所属类和包未其最近的定义或重写过的父类的类和包。
- 子类重写方法,使用了父引用调用方法,那么该方法属于父类(满足第一条),但是实际方法逻辑为子类。
因此只需要关注调用function所属类和function所属类 是否在相同包或是其子类即可判断能否可见
3. 验证各个包下是否可见
3.1 父亲包下验证
发现在父亲包下Test类调用侄子包里重写的方法失败。
这是因为父亲包下的Test类既不与侄子同包,又不是该侄子类的子类。
3.2 侄子包下验证
发现在侄子包下Test类调用儿子包下所有类的function方法和侄子包下侄子1和父function方法都失败
逐一说明:
- childOne、childTwo、childOneParent、childTwoParent都在父包下。侄子包下的Test类不属于他们的子类且包不同,因此无法访问
- nephewOneParent、nephewTwoParent的类型是Parent类,在父包下。因此包不同且非子类,无法访问。
- nephewOne 未重写 父类方法,所以调用function方法也是在调用父类方法,所以无法访问。
- nephewTwo 重写 父类方法,所以调用function方法时,Test类与function所在包相同,可以访问。
3.3 外人包下验证
包不同且Test非被调用者子类,所以无法访问