news 2026/2/26 8:50:54

面向对象编程三大特性:封装、继承、多态的核心要义

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面向对象编程三大特性:封装、继承、多态的核心要义

封装

封装是面向对象编程的基本原则,封装要求在编写类时,对外隐藏内部的数据状态和实现细节,仅对外暴露接口,用于外部调用访问。

类的封装,通常类的属性私有(用private修饰符),不对外暴露数据和实现细节,而是通过get和set方法获取和设置属性。

packageoop.classDemo2;publicclassTeacher{// 私有,不对外公开访问的实例属性privateStringname;privateintage;// 构造方法(方法重载)publicTeacher(Stringname,intage){this.name=name;this.age=age;}publicTeacher(Stringname){this.name=name;}publicTeacher(intage){this.age=age;}publicTeacher(){}// 实例方法publicvoidsetName(Stringname){this.name=name;}publicStringgetName(){returnthis.name;}publicvoidsetAge(intage){this.age=age;}publicintgetAge(){returnthis.age;}publicvoidsayWhoIam(){System.out.println("我叫"+this.name+",今年"+this.age+"岁,我是一名老师");}}

类的使用者,不能通过new一个对象,用对象.属性设置和获取数据,只能通过对象.方法设置和获取数据。

TeacherxiaoMing=newTeacher("小明",33);System.out.println(xiaoMing.age);// 错误代码,不能通过对象.属性名称 来访问属性System.out.println(xiaoMing.getAge());// 正确代码,通过get方法,来访问属性

为什么要这么做?为什么要多此一举编写get和set方法?

这样做的好处是:

  1. 有利于多人团队协作。类的编写者和调用者可以分开,类的调用者不需要关心和了解类的具体属性是什么,只需要调用方法(调用API)实现需要的操作即可。
  2. 便于维护和更新代码。编写一个类可以使用多种数据结构、不同的数据类型,如果属性的访问不是通过封装成方法,那更新编写类的数据结构,则调用类的代码也需要同步变更。而使用封装的方法,则在调用时不需要更新,因为类更换数据结构后,只需要更新适配新数据结构的get和set方法即可。
  3. 利于代码的安全性。通过set方法设置变量属性,可以做数据校验和特殊处理,有利于代码的安全性。

**注意:封装并不是要求把所有的私有属性通过setter和getter暴露出来,因为开放私有属性获取和设置,这本身可能就破坏了类的封装性

很多时候,类不提供setter和getter方法,而是直接提供业务相关的方法。

publicclassBankAccount{privatedoublebalance;publicBankAccount(){this.balance=0;}// 不直接提供setBalance,而是提供业务相关的方法publicvoiddeposit(doubleamount){if(amount>0){// 判断金额是否合法balance+=amount;}}publicbooleanwithdraw(doubleamount){if(amount>0&&balance>=amount){balance-=amount;returntrue;}returnfalse;}publicdoublegetBalance(){returnbalance;}// 注意:没有setBalance方法!}

继承

面向对象的编程,是以类来组织和封装代码。当类足够多时,我们会对类进行抽象,划分为所谓父类和子类,比如“动物”这个父类下,有“哺乳动物”、“脊椎动物”等子类。

从认知上,子类和父类一定有一些共同的属性特征,否则不可能抽象成一个父类。而子类一定会与父类有些差异或者特殊属性,否则页不可能被划分为子类。就像父类“教师”,可以划分为“生物教师”、“数学教师”子类。“数学教师”是(is a)“教师”,而“数学教师”又具备“教数学”特殊技能的特殊的“教师”。

什么是面向对象编程的继承?面向对象编程时,子类可继承父类的公开(public)属性和方法,这一特性可以大幅减少代码量,提高编程效率。

在Java中,父类又称为基类,子类又称为扩展类、派生类,因此使用关键字extends来标记子类。即

publicclassSonClassextendsFatherClass{// 子类体}

在Java中,子类可以继承父类的:

  1. 公开的静态属性
  2. 公开的静态方法
  3. 所有的实例属性,父类私有的(private)实例属性无法被直接访问,但是可以通过继承公开的(public protected)实例方法进行调用,间接获取父类的私有的实例属性。
  4. 公开的实例方法
    需要注意的是,子类不继承父类的构造方法,而是子类必须通过super()调用父类的构造方法。
publicclassApp{publicstaticvoidmain(String[]args){// MathTeacher继承Teacher的公开的静态属性System.out.println(MathTeacher.CLASS_NAME);// 老师// MathTeacher继承Teacher的公开的静态方法MathTeacher.sayHello();// Hello everyone, I am a teacher// MathTeacher继承Teacher的公开的实例属性MathTeacherzhangSan=newMathTeacher("张三",32);System.out.println(zhangSan.name);// 张三(name为父类的公开的实例属性)// MathTeacher继承Teacher的公开的实例方法System.out.println(zhangSan.getAge());// 32(age为父类的私有实例属性,通过公开的实例方法间接访问)}}
publicclassTeacher{// 静态属性publicstaticfinalStringCLASS_NAME="老师";// 静态方法publicstaticvoidsayHello(){System.out.println("Hello everyone, I am a teacher");}// 实例属性(一般是要封装成私有属性,此处为示例继承功能,两个属性分别用公开和私有)publicStringname;privateintage;// 构造方法publicTeacher(Stringname,intage){this.name=name;this.age=age;}// 实例方法publicintgetAge(){returnage;}}
publicclassMathTeacherextendsTeacher{// extends关键字继承父类// 继承了父类的公开的静态属性// 继承了父类的公开的静态方法// 继承了父类的公开的实例属性// 子类需要使用super()调用父类的构造方法publicMathTeacher(Stringname,intage){super(name,age);}// 继承了父类的公开的实例方法}

super

子类会继承父类的实例属性,子类构造方法需要使用super关键词,调用父类构造方法,初始化继承自父类的实例属性。

子类的构造方法,会隐式的调用super()。但是,如果父类的构造方法是有参构造,则子类必须显性的编写super()方法进行调用。如果显性编写super(),比如:

// 父类publicclassTeacher{privateStringname;privateintage;publicTeacher(){System.out.println("父类初始化了");}}
// 子类publicclassMathTeacherextendsTeacher{publicMathTeacher(){System.out.println("子类初始化了");}}
// 子类初始化publicclassApp{publicstaticvoidmain(String[]args){MathTeacherzhangSan=newMathTeacher();}}
父类初始化了 子类初始化了 进程已结束,退出代码为0

初始化子类时,会调用子类的构造方法。而在子类的构造方法内部,会隐式的调用super(),即调用父类的构造方法。因此,才会运行System.out.println(“父类初始化了”)。

需要注意: super()必须是子类构造方法的第一个语句。

方法重写

子类会继承父类公开的实例方法,但是很多情况下,父类的方法可能并不是子类需要的,或者子类需要的实例方法,运行逻辑与父类不同。这种情况下,就可以在子类重新定义与父类方法相同名称的实例方法,在实例调用时,会去运行子类定义的方法。这种情况,叫方法的重写。

子类重写的方法,可添加@override注解(非必须),可以帮助编译器检查方法重写是否正确。

需要注意:

  1. 方法重写指的是实例方法的重写,静态方法不存在重写。也就是父类和子类都存在相同的静态方法,此类情况并非方法的重写。
  2. 方法的重写,要求子类和父类方法的方法名、方法参数和范围值都相同,否则系统不会认定是方法的重写。
  3. 访问修饰符不能比父类更严格。(宽松程度:public > protected > default > private)
  4. 抛出异常:不能抛出比父类方法更宽泛的检查异常

Object类

Java是用类来组织代码,java中所有的类都隐式的继承自一个Object类,继承Object类的方法,比如使用hashcode、toString等方法。

多态

多态是指同一个方法,在不同的对象上调用,会产生不同的效果,。

多态是方法的多态,跟属性没有半毛钱关系。

面向对象的多态特性,表现在方法重载和方法重写。

方法重载的多态(编译时多态/静态多态)

方法重载,是指在java的同一个类中,可以定义多个具有相同方法名的方法,只需要满足:返回类型、方法参数(参数数量、参数类型、参数顺序)不同。

在方法被调用时,系统会根据形参自动选择对应的方法(在编译阶段,编译器会根据形参,绑定选用的方法,是静态绑定)。比如:

// 方法重载示例:同一个类中,方法名相同,参数列表不同classCalculator{// 加法方法的不同形式publicintadd(inta,intb){returna+b;}publicdoubleadd(doublea,doubleb){returna+b;}publicintadd(inta,intb,intc){returna+b+c;}}publicclassOverloadExample{publicstaticvoidmain(String[]args){Calculatorcalc=newCalculator();// 编译器根据参数类型和数量决定调用哪个方法System.out.println("两个整数相加: "+calc.add(5,10));// 调用 add(int, int)System.out.println("两个小数相加: "+calc.add(5.5,10.5));// 调用 add(double, double)System.out.println("三个整数相加: "+calc.add(5,10,15));// 调用 add(int, int, int)}}

方法重写的多态(运行时多态/动态多态)

方法重写,是发生在子类继承父类的场景里。方法重写,就是子类继承父类方法时,对相同的方法的代码逻辑进行重新编写。

当父类引用指向子类对象时,系统会动态的根据子类对象,调用子类对象的方法(在编译阶段,编译器会检查父类是否有需要调用的方法,而在运行阶段,系统会根据子类对象调用不同的方法,因此是动态绑定)。

// 父类classAnimal{publicvoidmakeSound(){System.out.println("动物发出声音");}}// 子类1classDogextendsAnimal{// 方法重写@OverridepublicvoidmakeSound(){System.out.println("汪汪汪!");}// 子类1狗特有的方法publicvoidwagTail(){System.out.println("狗摇尾巴");}}// 子类2classCatextendsAnimal{// 方法重写@OverridepublicvoidmakeSound(){System.out.println("喵喵喵!");}}// 子类3classBirdextendsAnimal{// 方法重写@OverridepublicvoidmakeSound(){System.out.println("叽叽喳喳!");}}publicclassPolymorphismExample{publicstaticvoidmain(String[]args){// 运行时多态:父类引用指向子类对象AnimalmyAnimal;myAnimal=newDog();// Animal引用指向Dog对象myAnimal.makeSound();// 输出:汪汪汪!myAnimal=newCat();// Animal引用指向Cat对象myAnimal.makeSound();// 输出:喵喵喵!myAnimal=newBird();// Animal引用指向Bird对象myAnimal.makeSound();// 输出:叽叽喳喳!// 示例:多态在数组中的应用Animal[]animals=newAnimal[3];animals[0]=newDog();animals[1]=newCat();animals[2]=newBird();System.out.println("\n动物合唱:");for(Animalanimal:animals){animal.makeSound();// 同一方法调用,不同行为}}}

方法重写是实例方法的重写,静态方法没有重写。静态方法可以被子类“隐藏”(hide),而不是重写。调用哪个版本取决于引用类型,而不是对象类型。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/25 6:49:54

AI赋能医学教育:从知识传递到能力塑造的革命

当医学生不再局限于书本图解和标本观察,而是能与AI虚拟病人沉浸式问诊、借助数字人解剖台探索人体奥秘,医学教育的传统边界正被人工智能彻底打破。广东医科大学AI医学院打造的“师-机-生”协同共创模式,正是AI技术深度赋能教育领域的生动实践…

作者头像 李华
网站建设 2026/2/23 0:44:20

初步了解Next.js

Next.js是React的一个超集框架,为什么会有Next.js这个框架存在呢,因为它可以解决React的痛点,就是客户端渲染 Next.js的一大亮点就是支持多模式混合渲染,分别有四种模式,CSR,SSR,SSG&#xff0c…

作者头像 李华
网站建设 2026/2/22 3:38:11

使用cmake构建Cplusplus版运行时库-–-behaviac

原文 请首先到/language/zh/downloads/下载或克隆源码。 缺省的,我们使用cmake来生成对应平台的项目文件(sln或make文件等)。 但cmake不是必须的,也可以选择自己喜欢的方式创建自己的项目文件。比如,使用premake等来…

作者头像 李华
网站建设 2026/2/22 14:30:18

pytesseract 中英文 识别图片文字

要使用 pytesseract 识别图片文字,你需要先安装 Tesseract OCR引擎 和 Pillow库,然后通过几行 Python 代码导入库、加载图片,并调用 image_to_string() 函数进行识别,传入图片路径和指定语言 (如 ‘eng’ 或 ‘chi_sim’) 即可获得文本内容。 步骤 1: 安装 Tesseract OCR引…

作者头像 李华
网站建设 2026/2/20 5:23:12

20、文件搜索、压缩与归档操作指南

文件搜索、压缩与归档操作指南 1. 文件搜索技巧 在日常的文件管理中,我们常常需要搜索特定的文件。传统的方式可能会多次执行命令,效率较低。为了提高效率,我们可以采用以下两种方法。 1.1 利用 find 命令的新特性 将 find 命令结尾的分号 ; 替换为加号 + ,就能…

作者头像 李华