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

Java 面向对象(OOP)的三大特性

封装

所谓封装,意思就是隐藏内部细节,在编程中,指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,并尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。

封装的最大特点就是降低了耦合性,外部无需知道内部的实现细节,只需使用就行了。

比如,在 Java 中,方法和类等都是一种封装。

public class Cat {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

继承

事物有分类的概念,比如动物、植物、猫、狗等,分类有个根,可以向下不断细化,形成一个层次分类体系。

编程语言使用继承来描述这种概念,在继承中,有父类(基类)和子类(派生类),比如动物类 Animal 和狗类 Dog,Animal 是父类,Dog 是子类。

继承实现了 IS-A 关系,比如 Animal 和 Dog,Dog is Animal 就是一种 IS-A 关系。

Java 继承是使用已经存在的类作为基础建立新类的技术,新类可以继承父类的数据或功能,还可以增加子类特有的数据或功能。

这样,公共的属性和行为可以放到父类中,而子类只需要关注子类特有的就可以了;另一方面,遵循里氏替换原则,不同的子类对象可以当成父类对象(即父类变量可以指向子类对象,称为向上转型),方便统一处理。

基本语法

Java 使用 extends 关键字表示继承关系,一个类最多只能有一个父类(单继承),默认父类是 java.lang.Object。

子类继承了父类的非私有属性和方法(构造方法除外),子类可以重写继承的父类方法(注意重写不能降低方法的访问权限),可以增加新的属性,新的方法,即子类可以在父类基础上进行重新实现和扩展。

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,可以抛出 IOException 异常或者 IOException 的子类异常。

注意:为什么不能方法重写时不能降低访问权限?因为继承体现的是 IS-A 关系,降低可见性会减少可以对外的行为,从而破坏了 IS-A 关系。

创建子类对象时,会先初始化父类的部分,子类构造方法默认会调用父类的无参构造方法,除非通过 super 手动调用父类的有参构造方法,父类必须要有无参构造方法。

super:在类的内部,可以通过 super 关键字明确访问父类的非私有属性、成员方法、构造方法,在子类构造方法中调用父类构造方法时,super 必须放在第一行。与 this 不同的是,super 不能指代具体的父类对象,不能作为参数值或返回值。

如果类被 final 修饰,则表示最终类,不能被继承,如 String 类;如果方法被 final 修饰,则该方法不能被子类重写。

public class Animal {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void eat(){System.out.println("吃...");}
}class Cat extends Animal {// @Override 注解,表示重写父类方法@Overridepublic void eat(){System.out.println(super.getName() + "猫猫爱吃小鱼鱼");}
}

谨慎继承

和分类体系相似,继承是一种逐级向上抽象的体系,因此继承是非常强大的,广泛应用于各种 Java API、框架和类库之中,提供了大量基类和基础公共代码。但继承也存在一些问题。

  • 继承可能破坏封装

封装就是隐藏实现细节,提供简化接口。使用者只需要关注怎么用,而不需要关注内部是怎么实现的。实现细节可以随时修改,而不影响使用者。

继承可能破坏封装是因为子类和父类之间可能存在着实现细节的依赖,更具体地说,子类需要知道父类的可重写方法之间的依赖关系,如果父类的方法之间存在调用依赖,而子类只重写了某个方法,就可能导致不可预测的错误。

父类也不能随意增加公开方法,因为给父类增加就是给所有子类增加,而子类可能必须要重写该方法才能确保方法的正确性。

  • 继承没有完全体现 IS-A 关系

比如,绝大部分鸟都会飞,可能就想给鸟类增加一个方法 fly() 表示飞,但有一些鸟就不会飞,比如企鹅。

  • 优先使用组合而非继承

使用组合可以抵挡父类变化对子类的影响,从而保护子类,应该优先使用组合。

public class Child {private Base base;private long sum;public Child(){base = new Base();}public void add(int number) {base.add(number);sum+=number;}public void addAll(int[] numbers) {base.addAll(numbers);for(int i=0; i<numbers.length; i++){sum+=numbers[i];}}public long getSum() {return sum;}
}

多态

多态分为编译时多态和运行时多态,编译时多态主要指方法的重载(overload),运行时多态指对象变量所指向的具体类型在运行期间才确定。

运行时多态有三个条件: 继承/实现;重写(覆盖);向上转型。

在 Java 中有两种形式实现运行时多态:继承和接口。

通过多态,Java 可以实现对不同类型的子类对象统一处理。

转型

转型分向上转型(子类转父类)和向下转型(父类转子类,需强转),实质是数据类型转换,当声明的数据类型与实际数据的类型不一致时,需要转型,而向上转型存在丢失数据或操作的问题。

Extend extend = new Extend();
Base base = extend; // 向上转型
extend = (Extend) base; // 向下转型,需强转

向下转型时,需要判断对象数据的实际类型是否与目标类型兼容(目标类型与实际类型一致,或者是两者某个中间层级的类型),如果不兼容,则无法转换,可以使用 instanceof 关键字判断。

if( base instanceof Extend) {extend = (Extend) base;
}

静态绑定和动态绑定

  • 静态类型:声明变量时的数据类型,通常是某个父类或接口。

  • 动态类型:创建对象时的数据类型。

在继承/实现体系中,存在成员重名的问题,可以认为此时子类对象有两份同名的成员变量或方法(父类部分和子类部分)。

对于 private 变量和方法,由于只能在类内访问,在父类中访问的是父类的,子类中访问的是子类的。

对于 public 成员,则看如何访问。在类的内部,默认带参数 this,访问的是类自身的,但子类可以通过 super 明确指定访问父类。

在类的外部,静态变量、静态方法、实例变量根据对象的静态类型判断,静态绑定,这符合数据类型向上转换后的特点。

对于实例方法,则根据对象的动态类型判断,动态绑定,因为 JVM 在实现多态的时候用的是 invokevirtual 指令,它会从子类部分开始往父类去寻找在所有重载版本中最匹配的方法。

静态绑定在程序编译阶段即可决定,而动态绑定则要等到程序运行时。

注意:动态绑定确认方法后,方法中对变量的访问由于默认带 this.,此时访问的是实际类中的变量。

class Base {public static int NUM;private int num;static {System.out.println("基类静态初始化代码块,NUM = "+ NUM);NUM = 10;}{System.out.println("基类实例初始化代码块,num = "+ num);num = 1;}public Base() {System.out.println("基类构造方法,num = " + num);num = 2;}protected void step() {System.out.println("基类,NUM = " + NUM + ",num = "+ num);}public void action(){step();}
}class Extend extends Base {public static int NUM;private int num;static {System.out.println("子类静态初始化代码块,NUM = "+ NUM);NUM = 100;}{System.out.println("子类实例初始化代码块,num = "+ num);num = 10;}public Extend() {System.out.println("子类构造方法,num = " + num);num = 20;}@Overrideprotected void step() {System.out.println("子类,NUM = " + NUM + ",num = "+ num);}}public class Test {public static void main(String[] args) {System.out.println("创建子类 === ");Extend extend = new Extend();System.out.println("子类 action === ");extend.action();Base base = extend;System.out.println("基类 action === ");base.action();System.out.println("基类访问类变量 === " + base.NUM);System.out.println("子类访问类变量 === " + extend.NUM);}
}

输出如下:

创建子类 === 
基类静态初始化代码块,NUM = 0
子类静态初始化代码块,NUM = 0
基类实例初始化代码块,num = 0
基类构造方法,num = 1
子类实例初始化代码块,num = 0
子类构造方法,num = 10
子类 action === 
子类,NUM = 100,num = 20
基类 action === 
子类,NUM = 100,num = 20
基类访问类变量 === 10
子类访问类变量 === 100

虚方法表

动态绑定的实现机制是从对象的实际类型开始往上逐级查找要执行的方法,如果继承的层次比较深,要调用的方法位于比较上层的父类,则每次调用都要进行多次查找,效率较低。

为此,大多数系统使用一种称为虚方法表的方法来优化调用的效率。

所谓虚方法表,就是在类加载的时候为每个类创建一个表,记录该类的对象所有动态绑定的方法(包括父类的方法)及其地址,一个方法只有一条记录,子类重写了父类方法后只会保留子类的。

这样,当动态绑定方法的时候,只需要查找实际类型的虚方法表就可以了。

参考:《Java 编程的逻辑》 马俊昌

相关文章:

Java 面向对象(OOP)的三大特性

封装 所谓封装&#xff0c;意思就是隐藏内部细节&#xff0c;在编程中&#xff0c;指利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体&#xff0c;并尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与外部发生联系。…...

Java:openjdk: error: Student is abstract; cannot be instantiated;java编译环境

文章目录编译环境jdkopenjdk错误代码小心javac -verbos编译环境 jdk 需要安装的javac 在java-devel 包里 [root10 ~]# rpm -qf /usr/bin/javac file /usr/bin/javac is not owned by any package [root10 ~]# ll /usr/bin/javac lrwxrwxrwx. 1 root root 23 Jun 15 09:52 /us…...

28个案例问题分析---019---临时解决方案和最终解决方案--思想

临时解决方案与最终解决方案一&#xff1a;背景介绍二&#xff1a;临时解决方案&#xff1f;最终解决方案&#xff1f;概念如何选择三&#xff1a;总结一&#xff1a;背景介绍 项目中&#xff0c;出现了一个线上问题。 用户登陆之后看不到课程。重新登陆就可以看到课程。出现这…...

计算机网络的166个概念你知道几个 第四部分

HTML&#xff1a;HTML 称为超文本标记语言&#xff0c;是一种标识性的语言。它包括一系列标签&#xff0e;通过这些标签可以将网络上的文档格式统一&#xff0c;使分散的 Internet 资源连接为一个逻辑整体。HTML 文本是由 HTML 命令组成的描述性文本&#xff0c;HTML 命令可以说…...

Lenovo 联想-IdeaPad-Y530电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板联想-IdeaPad-Y530处理器Intel 酷睿2双核 T9400已驱动内存2GB已驱动硬盘2TB HP EX950 PCI-E Gen3 x4 NVMe SSD已驱动显卡NVIDIA GeForce 9300M GS无法驱动声卡Realtek ALC888无法驱动网卡RTL8168H Giga…...

mac M1 nvm安装教程,避坑

mac M1 nvm 安装问题 新款的mac搭载了苹果自研的芯片&#xff0c;放弃了intel的x86芯片&#xff0c;那之前的软件难免会存在兼容性问题。 鄙人有幸踩了第一个坑。 在通过nvm 安装不同版本的node 时&#xff0c;出现了问题。 问题一&#xff1a;先说一下 nvm的安装问题&#…...

【项目精选】基于网络爬虫技术的网络新闻分析(视频+论文+源码)

点击下载源码 基于网络爬虫技术的网络新闻分析主要用于网络数据爬取。本系统结构如下&#xff1a; &#xff08;1&#xff09;网络爬虫模块。 &#xff08;2&#xff09;中文分词模块。 &#xff08;3&#xff09;中3文相似度判定模块。 &#xff08;4&#xff09;数据结构化存…...

【Python - Matplotlib】P2 plot 折线图

Matplotlib绘制折线图折线图完整代码与效果基础折线图设定横纵坐标设置中文显示添加网格添加描述信息再添加一个城市设置两个折线图前言 上一节内容主要围绕介绍 Matplotlib 的画板结构。 链接&#xff1a;https://blog.csdn.net/weixin_43098506/article/details/129331576 本…...

【Verilog】——模块,常量,变量

目录 1.模块 1.描述电路的逻辑功能 2. 门级描述 3.模块的模板​编辑 2.关键字 3.标识符 4.Verilog源代码的编写标准 5.数据类型 1.整数常量​ 2.参数传递的两种方法 3.变量 4.reg和wire的区别 5.沿触发和电平触发的区别​ 6.memory型变脸和reg型变量的区别​ 1.模块 1.描…...

论文投稿指南——中文核心期刊推荐(电影、电视艺术)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…...

Pip install 和Conda install 总结

版本一 conda install xxx&#xff1a;这种方式安装的库都会放在/Users/orion-orion/miniforge3/pkgs目录下。我们在我们的虚拟环境中要用到或下载时先到该路径下去找&#xff0c;若有则直接将其复制到我们的虚拟环境中包得存放位置: ~/site-packages/。若没有&#xff0c;则先…...

嵌入式系统实验——【玄武F103开发板】实现两个LED小灯闪烁

目录一、实验文件main.cstm32f10x.h二、实验思路&#xff08;一&#xff09;打开两个LED小灯1.在玄武F103开发板上找到LED0、LED1对应的GPIO控制寄存器2.找到GPIOB、GPIOE的地址3.打开APB2外设时钟的使能寄存器4.对GPIO寄存器进行设置对端口输出寄存器进行设置&#xff08;二&a…...

数组之双指针题

文章目录一、最长连续不重复子序列1.题目介绍2.思路3.二、长度最小的子数组1.题目介绍2.思路3.代码三、数组元素的目标和1.题目介绍2.思路3.代码总结其实在之前我写过不少双指针得题解&#xff0c;刷题专练之数组移除元素 刷题专练之翻转题练习这两篇文章的题解基本就是双指针法…...

真实需求和梦想实现满足

多少的时光和岁月中都不曾认真系统的深度思考自己的真实需求和欲望之间是否一致&#xff0c;随着时间的流逝才发现自己追求的是一场空&#xff0c;自己的真实需求并不是苦苦追求的东西&#xff0c;这也是当梦想照进现实&#xff01;欲望是无善无恶的&#xff0c;不必为了满足自…...

[ant-design-vue] tree 组件功能使用

[ant-design-vue] tree 组件功能使用描述环境信息相关代码参数说明描述 是希望展现一个树形的菜单&#xff0c;并且对应的菜单前有复选框功能&#xff0c;但是对比官网的例子&#xff0c;我们在使用的过程中涉及到对半选中情况的处理&#xff1a; 半选中状态&#xff1a; 选中…...

QT父子窗口事件传递与事件过滤器

处理监控系统的时候遇到问题&#xff0c;在MainWidget中创建多个子Widget的时候&#xff0c;原意是想鼠标点击先让MainWidget截获处理后再分派给子Widget去处理&#xff0c;但调试后发现如果子Widget重新实现了事件方法&#xff0c;就直接处理掉事件了&#xff0c;没有进到Main…...

【2.4 golang中的循环语句for】

- 循环语句for 1. 循环语句for 1.1.1. Golang for支持三种循环方式&#xff0c;包括类似 while 的语法。 for循环是一个循环控制结构&#xff0c;可以执行指定次数的循环。 语法 Go语言的For循环有3中形式&#xff0c;只有其中的一种使用分号。 for init; condition; pos…...

Windows 系统下 Apache 和 php 环境怎么搭建?

传统搭建方法在 Windows 系统下&#xff0c;可以通过以下步骤来搭建 Apache 和 PHP 环境&#xff1a;1.下载 Apache 在 Apache 官网下载最新版本的 Apache&#xff0c;例如下载地址为 https://httpd.apache.org/download.cgi。2.安装 Apache 将下载的 Apache 压缩包解压到某个目…...

Python基础知识——字符串、字典

字符串 在Python中&#xff0c;字符和字符串没有区别。可能有些同学学过其他的语言&#xff0c;例如Java&#xff0c;在Java中&#xff0c;单引号’a’表示字符’a’&#xff0c;双引号"abc"表示字符串"abc"&#xff0c;但在Python当中&#xff0c;它们没…...

JVM常用指令

JVM常用指令1.准备工作2.jps3. jconsole4.jstat5.jstack6.jmap7.jvisualvm工具8.自动dump内存信息1.准备工作 在idea中编写代码 public class JVMTest {Testpublic void test() throws InterruptedException {while (true) {Thread.sleep(1000);System.out.println(123);}} }…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...