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 OKbasicObj.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 OKbasicObj.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 OKfirstKid1_obj.basic();// Compile OKSecondKid1 secondKid1_obj = new SecondKid1();System.out.print(secondKid1_obj.name);// Compile OKsecondKid1_obj.basic();// Compile OKSecondKid2 SecondKid2_obj = new SecondKid2();System.out.print(SecondKid2_obj.name);// Compile OKSecondKid2_obj.basic();// Compile OKThirdKid1 thirdKid1_obj = new ThirdKid1();System.out.print(thirdKid1_obj.name);// Compile OKthirdKid1_obj.basic();// Compile OKBasic 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 failSecondKid1 secondKid1_obj = new SecondKid1();System.out.print(secondKid1_obj.name);// Compile OKsecondKid1_obj.basic();// Compile OKSecondKid2 secondKid2_obj = new SecondKid2();//System.out.print(secondKid2_obj.name);// Compile fail//secondKid2_obj.basic();// Compile failThirdKid1 thirdKid1_obj = new ThirdKid1();System.out.print(thirdKid1_obj.name);// Compile OKthirdKid1_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 failSecondKid2 secondKid2_obj = new SecondKid2();System.out.print(secondKid2_obj.name);// Compile OKsecondKid2_obj.basic();// Compile OKSecondKid1 secondKid1_obj = new SecondKid1();//System.out.print(secondKid1_obj.name);// Compile fail//secondKid1_obj.basic();// Compile failThirdKid1 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 failSecondKid1 secondKid1_obj = new SecondKid1();//System.out.print(secondKid1_obj.name);// Compile fail//secondKid1_obj.basic();// Compile failThirdKid1 thirdKid1_obj = new ThirdKid1();System.out.print(thirdKid1_obj.name);// Compile OKthirdKid1_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 OKsecondKid1_obj.basic();// Compile OK}
}
对于继承自Basic的子类FirstKid2:

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

package p2;import p1.Basic;public class FirstKid2 extends Basic {protected String name = "Arcsin";@Overrideprotected 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 OKfirstKid2_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成员,其后续子类都将以这一中间子类为新的基类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36384.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MSys2统一开发环境,快速搭建windows opencv环境

文章目录 摘要下载msys2安装Mingw64安装Cmake安装opencv报错一报错二问题一 摘要 本篇基于之前发布的opencv两篇文章,进行的流程简化,旨在优化windows opencv环境和实例运行,Msys2统一开发环境,有利于长远的开发环境,也简化了后续集成的难度…

基于单片机的多功能热水器设计(论文+源码)

1系统方案设计 基于单片机的多功能热水器系统,其系统框图如图2.1所示。主要采用了DS18B20温度传感器,HC-SR04超声波模块,STC89C52单片机,液晶,继电器等来构成整个系统。硬件上主要通过温度传感器进行水温的检测&am…

详解Sympy:符号计算利器

Sympy是一个专注于符号数学计算的数学工具,使得用户可以轻松地进行复杂的符号运算,如求解方程、求导数、积分、级数展开、矩阵运算等。其中比较流行的深度学习框架pytorch的用到了Sympy,主要用于将模型的计算图转换为符号化表达式,以便进行分…

《Python实战进阶》No27: 日志管理:Logging 模块的最佳实践(上)

No27: 日志管理:Logging 模块的最佳实践(上) 摘要 日志记录是软件开发中不可或缺的一部分,尤其是在复杂的生产环境中。Python 的内置 logging 模块提供了强大的工具来管理和记录程序运行中的各种信息。本集将深入探讨 logging 模块的核心概念&#xff0…

每日Attention学习27——Patch-based Graph Reasoning

模块出处 [NC 25] [link] Graph-based context learning network for infrared small target detection 模块名称 Patch-based Graph Reasoning (PGR) 模块结构 模块特点 使用图结构更好的捕捉特征的全局上下文将图结构与特征切片(Patching)相结合,从而促进全局/…

ospf动态路由

一、为什么使用动态路由 OSPF(open shortest path first开放最短路径优先)是内部网关协议(IGP)的一种,基于链路状态算法(LS)。 OSPF企业级路由协议(RFC2328 OSPFv2),核心重点协议 OSPF共三个版本,OSPFV1主要是实验室…

记一次服务器中木马导致cpu占用高的问题

最近准备搭建一个个人博客,发现才放了一个nginx和一个很简单的java后台cpu占用率就居高不下,然后用top命令查看果然有问题 其中这个networkservice 和sysupdate占用很高,原本还以为是系统相关的进程,但是想想如果是系统相关的进程…

基于LabVIEW的Windows平台高速闭环控制

在Windows系统下,通过LabVIEW实现高速闭环控制面临两大核心挑战:非实时操作系统的调度延迟与硬件接口的传输速度限制。以USB-6351(NI USB-6351 DAQ卡)为例,其理论采样率可达1.25 MS/s(单通道)&a…

深入理解 Linux ALSA 音频架构:从入门到驱动开发

文章目录 一、什么是 ALSA?二、ALSA 系统架构全景图核心组件详解:三、用户空间开发实战1. PCM 音频流操作流程2. 高级配置(asound.conf)四、内核驱动开发指南1. 驱动初始化模板2. DMA 缓冲区管理五、高级主题1. 插件系统原理2. 调试技巧3. 实时音频优化六、现代 ALSA 发展七…

【C语言】自定义类型:结构体

一、结构体类型的声明 我们前面学习操作符的时候已经接触过结构体了,下面我们回顾一下结构体的基本内容。 创建结构体的语法如上所示: struct是创建结构体的关键字,然后tag就是我们结构体的名称,member-list是结构体的成员列表&…

python基本运用:类的介绍和使用

一、介绍类 类(class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例 实例化:创建一个类的实例,类的具体对象。 对象:通过类定义的数据结构实例。对象包括两个数据成员&#x…

Elasticsearch:使用 ColPali 进行复杂文档搜索 - 第 1 部分 - 8.18

作者:来自 Elastic Peter Straer 及 Benjamin Trent 这篇文章介绍了 ColPali 模型,这是一种 late-interaction 模型,可简化包含图片和表格的复杂文档搜索过程,并讨论了其在 Elasticsearch 中的实现。 在构建搜索应用时&#xff0c…

2025-03-19 学习记录--C/C++-C 库函数 - qsort() 实现快速排序

C 库函数 - qsort() 实现快速排序 ⭐️ C 标准库 - <stdlib.h> &#xff08;一&#xff09;、命名介绍 &#x1f36d; qsort 是 C 标准库&#xff08;stdlib.h&#xff09;中提供的一个快速排序函数&#xff0c;用于对数组进行排序。❀它的名字来源于 “Quick Sort”&…

04 泛型编程

1、概论 编程范式&#xff1a;面向过程编程、面向对象编程、泛型编程。 泛型编程&#xff1a;目的是编写能够适合多种数据类型的代码&#xff0c;而不是为每种特定的数据类型编写重复的代码。 模板是实现泛型的主要工具&#xff0c;主要分为函数模板和类模板。 函数模板&am…

【MySQL】架构

MySQL架构 和其它数据库相比&#xff0c;MySQL有点与众不同&#xff0c;它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上&#xff0c;插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可以根据业务的需求和实…

(保姆级教程)CAN总线—如何使用CANoe(VN1640)的Scaner功能测量样件的波特率

1、如何找到测试入口 &#xff08;步骤1&#xff09;前置条件 连接好被测样件和VN1640&#xff0c;连接电源。 &#xff08;2&#xff09;打开CANoe工程&#xff0c;依次点击Hardware--》NetworkHardware&#xff0c;如下图&#xff1a; &#xff08;3&#xff09;单击Netwo…

使用 PIC 微控制器和 Adafruit IO 的基于 IoT 的 Web 控制家庭自动化

使用 PIC 微控制器和 Adafruit IO 的基于 IoT 的 Web 控制家庭自动化 家庭自动化一直是我们大多数人的灵感来源。从我们舒适的椅子或任何房间的床上切换交流负载,而无需伸手去触碰另一个房间的开关,听起来很酷,不是吗!.现在,在物联网时代,多亏了 ESP8266 模块,它使从世界…

MySQL原理:逻辑架构

目的&#xff1a;了解 SQL执行流程 以及 MySQL 内部架构&#xff0c;每个零件具体负责做什么 理解整体架构分别有什么模块每个模块具体做什么 目录 1 服务器处理客户端请求 1.1 MySQL 服务器端逻辑架构说明 2 Connectors 3 第一层&#xff1a;连接层 3.1 数据库连接池(Conn…

Excel Script Lab学习笔记

注意 The Excel JavaScript API 没有“Cell”对象或类。 相反&#xff0c;Excel JavaScript API 将所有 Excel 单元格定义为 Range 对象。 Excel UI 中的单个单元格转换为 Excel JavaScript API 中包含一个单元格的 Range 对象。 单个 Range 对象也可以包含多个连续的单元格。…

【第14节】windows sdk编程:进程与线程介绍

目录 一、进程与线程概述 1.1 进程查看 1.2 何为进程 1.3 进程的创建 1.4 进程创建实例 1.5 线程查看 1.6 何为线程 1.7 线程的创建 1.8 线程函数 1.9 线程实例 二、内核对象 2.1 何为内核对象 2.2 内核对象的公共特点 2.3 内核对象句柄 2.4 内核对象的跨进程访…