当前位置: 首页 > news >正文

Java protected 关键字详解及探究过程(详细、准确)

参考菜鸟教程:Java protected 关键字详解,初步学习了protected可见性相关的内容,但发现其仍有不足之处,特此自行探究。

protected可见性:

先给出关于protected可见性的结论:

protected可见性遵循这样的优先级 1 -> 2 -> 3:

  1. 基类的protected成员,首先是基类内部可见的
  2. 其次是“和基类同一包内的其他类”也可见的
  3. 然后是“和基类不同包,是其子类通过一定方式可见的:实际上任意子类可以通过创建其自身的实例来访问基类的protected成员,或创建其子类的实例来访问基类的protected成员,但不能通过创建父类或无直接继承关系的其他类的实例来访问基类的protected成员。

注意

  • 基类是绝对的,即此处某个protected成员的源头;父类是相对的,即此处某个protected成员的直接来源
  • 由于protected可见性遵循优先级,比方说:某个子类创建了父类的实例来尝试访问基类的protected成员,但是该子类和基类位于同一包内(优先级2),那么也能够成功访问。

protected可见性的探究:

通过// Compile OK表示编译成功,// Compile fail表示编译失败。

1. 基类的protected成员,首先是基类内部可见的:

package p1;

public class Basic {
    protected String name = "Aqua's Basic";
    protected void basic() {System.out.println(" say Hello to you");}
    
    public static void main(String[] args) {
        Basic basicObj = new Basic();
        System.out.print(basicObj.name);// Compile OK
        basicObj.basic();// Compile OK
    }
}

2. 其次是“和基类同一包内的其他类”也可见的

package p1;

public class Another {
    public static void main(String[] args) {
        Basic basicObj = new Basic();
        System.out.print(basicObj.name);// Compile OK
        basicObj.basic();// Compile OK
    }
}

3. 和基类不同包的子类

有继承关系如下:

Basic -> FirstKid1;

FirstKid1 -> SecondKid1, SecondKid2;

SecondKid1 -> ThirdKid1;

对于FirstKid1:

调用FirstKid1类自身的实例,实际上是访问FirstKid1类自身继承的protected成员

调用FirstKid1类的任意子类的实例,实际上是子类的实例访问该子类中继承的protected成员

package p2;

import p1.Basic;
import p3.SecondKid2;

public class FirstKid1 extends Basic{
    public static void main(String[] args) {
        FirstKid1 firstKid1_obj = new FirstKid1();
        System.out.print(firstKid1_obj.name);// Compile OK
        firstKid1_obj.basic();// Compile OK

        SecondKid1 secondKid1_obj = new SecondKid1();
        System.out.print(secondKid1_obj.name);// Compile OK
        secondKid1_obj.basic();// Compile OK

        SecondKid2 SecondKid2_obj = new SecondKid2();
        System.out.print(SecondKid2_obj.name);// Compile OK
        SecondKid2_obj.basic();// Compile OK

        ThirdKid1 thirdKid1_obj = new ThirdKid1();
        System.out.print(thirdKid1_obj.name);// Compile OK
        thirdKid1_obj.basic();// Compile OK

        Basic basicObj = new Basic();
        //System.out.print(basicObj.name);// Compile fail
        //basicObj.basic();// Compile fail
    }
}
对于SecondKid1和SecondKid2:

两者位于不同包中,但都继承自FirstKid1。

均可创建自身的实例以访问继承的protected成员。

均不可创建父类FirstKid1的实例以访问protected成员,报错信息为 "'basic()'在'p1.Basic'中具有protected访问权限"。

但是两者相互之间无继承关系,因此无法借助对方的实例对protected成员进行访问,报错信息为 "'basic()'在'p1.Basic'中具有protected访问权限"。

package p2;

import p1.Basic;
import p3.SecondKid2;

public class SecondKid1 extends FirstKid1{
    public static void main(String[] args) {
        FirstKid1 firstKid1_obj = new FirstKid1();
        //System.out.print(firstKid1_obj.name);// Compile fail
        //firstKid1_obj.basic();// Compile fail

        SecondKid1 secondKid1_obj = new SecondKid1();
        System.out.print(secondKid1_obj.name);// Compile OK
        secondKid1_obj.basic();// Compile OK

        SecondKid2 secondKid2_obj = new SecondKid2();
        //System.out.print(secondKid2_obj.name);// Compile fail
        //secondKid2_obj.basic();// Compile fail

        ThirdKid1 thirdKid1_obj = new ThirdKid1();
        System.out.print(thirdKid1_obj.name);// Compile OK
        thirdKid1_obj.basic();// Compile OK
    }
}

package p3;

import p2.FirstKid1;
import p2.SecondKid1;
import p2.ThirdKid1;

public class SecondKid2 extends FirstKid1 {
    public static void main(String[] args) {
        FirstKid1 firstKid1_obj = new FirstKid1();
        //System.out.print(firstKid1_obj.name);// Compile fail
        //firstKid1_obj.basic();// Compile fail

        SecondKid2 secondKid2_obj = new SecondKid2();
        System.out.print(secondKid2_obj.name);// Compile OK
        secondKid2_obj.basic();// Compile OK

        SecondKid1 secondKid1_obj = new SecondKid1();
        //System.out.print(secondKid1_obj.name);// Compile fail
        //secondKid1_obj.basic();// Compile fail

        ThirdKid1 thirdKid1_obj = new ThirdKid1();
        //System.out.print(thirdKid1_obj.name);// Compile fail
        //thirdKid1_obj.basic();// Compile fail
    }
}
对于ThirdKid1:

ThirdKid1继承自SecondKid1,依然不能通过SecondKid1或FirstKid1的实例访问protected成员,报错信息为 "'basic()'在'p1.Basic'中具有protected访问权限"。

在SecondKid1类中,可以创建ThirdKid1的实例访问protected成员。

在SecondKid2类中,无法通过ThirdKid1的实例访问protected成员。报错信息为 "'basic()'在'p1.Basic'中具有protected访问权限"。

package p2;

public class ThirdKid1 extends SecondKid1{
    public static void main(String[] args) {
        FirstKid1 firstKid1_obj = new FirstKid1();
        //System.out.print(firstKid1_obj.name);// Compile fail
        //firstKid1_obj.basic();// Compile fail

        SecondKid1 secondKid1_obj = new SecondKid1();
        //System.out.print(secondKid1_obj.name);// Compile fail
        //secondKid1_obj.basic();// Compile fail

        ThirdKid1 thirdKid1_obj = new ThirdKid1();
        System.out.print(thirdKid1_obj.name);// Compile OK
        thirdKid1_obj.basic();// Compile OK
    }
}
报错信息的补充解释:

"'basic()'在'p1.Basic'中具有protected访问权限",说明对于未覆盖的protected成员,子类访问时,实际上是访问基类的protected成员。

对于与基类Basic同包的第三孩子ThirdKid2:

也能够创建其父类SecondKid1的实例以访问protected成员,根本原因是ThirdKid2与Basic同包,因此可以直接访问基类的protected成员。

package p1;

import p2.SecondKid1;

public class ThirdKid2 extends SecondKid1 {
    public static void main(String[] args) {
        SecondKid1 secondKid1_obj = new SecondKid1();
        System.out.print(secondKid1_obj.name);// Compile OK
        secondKid1_obj.basic();// Compile OK
    }
}
对于继承自Basic的子类FirstKid2:

通过覆盖,改变访问的对象。

package p2;

import p1.Basic;

public class FirstKid2 extends Basic {
    protected String name = "Arcsin";
    @Override
    protected void basic() {System.out.println(" say 你好 to you");}
    public static void main(String[] args) {
        FirstKid2 firstKid2_obj = new FirstKid2();
        System.out.print(firstKid2_obj.name);// Compile OK
        firstKid2_obj.basic();// Compile OK
    }
}
/*
输出内容:
Arcsin say 你好 to you
*/
对于SecondKid3:

虽然SecondKid3跟Basic同包,但继承自FirstKid2。

由于FirstKid2中的protected成员覆盖了(继承自)Basic的protected成员,因此对于SecondKid3,它的基类不是Basic,而是FirstKid2。

而SecondKid3与FirstKid2不同包,无法创建其实例以访问protected成员,报错信息 " 'basic()'在'p2.FirstKid2'中具有protected访问权限 ",证明了基类的改变。

package p1;

import p2.FirstKid2;

public class SecondKid3 extends FirstKid2 {
    public static void main(String[] args) {
        FirstKid2 firstKid2_obj = new FirstKid2();
        //System.out.print(firstKid2_obj.name);// Compile fail
        //firstKid2_obj.basic();// Compile fail
    }
}

总结:

对于未覆盖的protected成员,任意类尝试访问时,实际上是访问基类的protected成员,能否访问成功,由protected可见性决定。

相对应的,当某一中间子类覆盖了原先的protected成员,其后续子类都将以这一中间子类为新的基类

相关文章:

  • 实验二 进程通信
  • CVPR2025 | AnyAttack:对任意图像的视觉语言模型的目标性对抗攻击
  • 实现拖拽图片验证的基本步骤
  • vulhub Matrix-Breakout
  • Ai知识库私有化部署
  • Android Launcher3 首屏图标锁定技术方案解析
  • What a code!
  • 网格交易中倍数委托的实现方法
  • 软考程序员考试知识点汇总
  • 华为ipd流程华为流程体系管理华为数字化转型流程数字化管理解决方案介绍81页精品PPT
  • 漏洞知识点《Tornado框架中RequestHandler的对象》
  • 英语词性--连词
  • Model Context Protocol - Prompts
  • 智慧楼宇:科技编织的未来生活图景
  • dart学习记录3(函数)
  • 三.ffmpeg对yuv的操作
  • SSH连接中断原因分析(SSH断开、SSH中断、SSH连接断开、远程断开、远程中断)(带宽不足、网络抖动与丢包、CPU资源耗尽、内存不足、磁盘I/O瓶颈)
  • 解锁物联网高效开发,Synaptics SYN43756E Wi-Fi 6E 芯片登场
  • 打造无缝智慧照明场景,涂鸦智能全新发布蓝牙Mesh照明解决方案
  • AI Agent系列(六) -基于ReAct架构搭建LLM Agent(Deepseek)
  • “行人相撞案”现场视频公布,法院:表述不当造成误导
  • 见微知沪|优化营商环境,上海为何要当“细节控”自我加压?
  • 上海如何为街镇营商环境赋能?送政策、配资源、解难题、强活力
  • 一季度全国消协组织为消费者挽回经济损失23723万元
  • 央行行长详解降息:将通过利率自律机制引导商业银行相应下调存款利率
  • 俄乌交换205名被俘人员,俄方人员已抵达白俄罗斯