Java面向对象-封装、继承、多态
每个组件都可以是一个有属性和方法的对象。让组件工作,要知道每个组件是怎么用的以及是如何与其他组件进行交互的,而无需了解这些组件内部是如何工作的。
面向过程的范式重点在于设计方法。面向对象的范式将数据和方法耦合在一起构成对象。使用面向对象方式的软件设计重点在于对象以及对对象的操作上。在面向过程程序设计中,数据和数据上的操作是分离的,即要求传递数据给方法。
在面向对象程序设计中,将数据和对他们的操作都放在一个对象中。
面向对象程序设计方法以一种反映真实世界的方式组织程序,在真实世界中,所有的对象和属性以及动作都相关联。(使用对象提供软件的可重用性、可维护性和可扩展性等)。
Java程序设计设计对对象的思考,一个Java程序可以看做是一个相互操作对象的集合。
面向对象的设计原则
- 单一职责原则(SRP,The Single Responsibility Principle): 当需要修改某个类的时候原因有且只有一个,让一个类只做一种类型责任。
- 开放与关闭原则(OCP,The Open Closed Principle):软件实体是可扩展而不可修改的,对扩展开发而对修改是关闭的。
- 里氏代换原则(LSP,The Liskov Substitution Principle):当一个子类的实例应该能够替换和人其超类的实例时才具有is-a关系。
- 接口分离原则(ISP, The Interface Seregation Principle):接口专门化,不要出现泛性接口职责不单一不规范。
- 依赖倒转原则(DIP,The Dependency Inversion Principle):高层模块不依赖于底层模块二者都应依赖于抽象且抽象不应该依赖于细节。
面向对象概念
面向对象编程, 是一种通过OOP,把现实世界映射到计算机模型的一种编程方法。
现实世界实体 | 计算机模型 | Java代码 |
---|---|---|
人 | 类 / class | class Person { } |
小明 | 实例 / ming | Person ming = new Person() |
小红 | 实例 / hong | Person hong = new Person() |
-
类和对象(实例)
类-class:对象共性的集合(类实质是一种数据类型)
对象-instance:类个性的体现 (某个对象是类的多个实例中的一个) -
在OOP中,class和instance是“模版”和“实例”的关系;
定义class就是定义了一种数据类型,对应的instance是这种数据类型的实例;
class定义的field,在每个instance都会拥有各自的field,且互不干扰;
通过new操作符创建新的instance,然后用变量指向它,即可通过变量来引用这个instance;
访问实例字段的方法是变量名.字段名;
指向instance的变量都是引用变量。
继承(关系是:is-a,父类更通用,子类更具体。)
什么是继承?
从已有的类派生出新的类称为继承。
为什么使用继承?
在不同的类中可能会有共同的特征和动作,可以把这些共同的特征和动作放在一个类中,让其他类共享。
继承是 Java 中实现软件重用的重要手段,避免重复,易于维护,易于理解。
- 父类和子类
类 B 从类 A 派生,或者说类 B 扩展自类 A,或者说类 B 继承类 A,
类 A 为"父类",也称为超类、基类;
B 为"子类",也称为次类、扩展类、派生类。
class 父类{ } class 子类 extends 父类{ // 子类从它的父类中继承可访问的数据域和方法,也可以添加新的数据域和新的方法。 }
继承具体使用
class Person { // ⭐️ -> 超类、父类、基类 private String name; private int age; public String getName() {...} public void setName(String name) {...} public int getAge() {...} public void setAge(int age) {...} } /** * 通过继承,Student只需要编写额外的功能,不再需要重复代码。 * ⚠️ 子类自动获得了父类的所有字段,严禁定义与父类重名的字段! */ class Student extends Person { // ⭐️ 子类、扩展类 // 不要重复name和age字段/方法, // 只需要定义新增score字段/方法: private int score; public int getScore() { … } public void setScore(int score) { … } }
- 继承结构:
子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的.*
向上转型
由于Student作为Person的子类可以实现子类实例指向父类引用
即:Person person = new Student()
原因: Student继承自Person拥有Person的全部功能。Person类型的变量。
把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)
向上转型是把一个子类型安全地变为更加抽象的父类型:
Student student = new Student(); Person person = student; // upcasting, ✅ Object object01 = person; // upcasting, ✅ Object object02 = student; // upcasting, ✅
继承树:Student > Person > Object( 子类扩展父类 )
向下转型
把一个父类类型强制转型为子类类型,就是向下转型(downcasting)
但实际上父类类型本质上指向的还是子类的实例否则将出现错误
向下转型不会把父类变成子类,因为子类扩展自父类比父类有更多的数据域和方法
Person p = new Person(); System.out.println(p instanceof Person); // true System.out.println(p instanceof Student); // false Student s = new Student(); System.out.println(s instanceof Person); // true System.out.println(s instanceof Student); // true Student n = null; System.out.println(n instanceof Student); // false
区分继承和组合
class Student extends Person{ private int StuNumber; // 一个学生只能存在一个学号 private List<Phone> phonesList; // 一个学生可以有多部手机📱 }
Student 和 Person之间是一种继承关系(is-a)即 学生是一种人
Student 和 List
小结
- 继承是OOP中代码复用的重要方式带来代码耦合度的提高
- Java只允许单继承,所有类最终的根类是Object;(多继承通过接口可以是实现)
- protected允许子类访问父类的字段和方法;
- 子类的构造方法可以通过super()调用父类的构造方法;
- 可以安全地向上转型为更抽象的类型;
- 可以强制向下转型,最好借助instanceof判断;
- 子类和父类的关系是is,has关系不能用继承。
封装:保证数据域的完整性
封装(Encapsulation)是一种将抽象性函数式接口的实现细节部分包装、隐藏起来的方法。
封装被认为是一种保护屏障,防止该类的代码和数据被外部类随意篡改
要访问该类的数据域需通过该类相关提供的统一接口。
封装具体应用
- 隐藏数据一般限制为private)
Eg:
public class Person{ // 将name和age属性设置为私有的,只能本类才能访问,其他类无法访问即可对信息隐藏 private String name; private int age; }
- 提供向外统一访问的接口(用于对私有属性的访问)
public class Person{ private String name; private int age; public int getAge(){ return age; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public void setName(String name){ this.name = name; } }
采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
多态
多态就是同一个接口,使用不同的实例而执行不同操作
多态实现的三个必要条件
- 继承
- 重写
- 父类引用指向子类实例(多态是指同一接口,使用不同实例执行不同操作)
eg:Person person = new Student()
多态具体应用
class Gun{ private String gunName; protected Gun(String gunName){ } protected void getInfo(String guanName){ } } class AK47Rifle extends Gun{ public AK47Rifle(String gunName){ super(gunName); getInfo(gunName); } @Override public void getInfo(String gunName) { System.out.println("AK47Rifle系列 - " + gunName + " - : 连续射击!"); } } class BarrettSniperRifle extends Gun{ protected BarrettSniperRifle(String gunName) { super(gunName); getInfo(gunName); } @Override public void getInfo(String gunName){ System.out.println("BarrettSniperRifle系列 - " + gunName + " - : 单点射击!"); } } public class AlgorithmDemoSpace { public static void main(String[] args) { Gun gun01 = new AK47Rifle("56式步枪"); Gun gun02 = new BarrettSniperRifle("巴雷特狙击步枪"); } } /* * 输出 * AK47Rifle系列 - 56式步枪 - : 连续射击! * BarrettSniperRifle系列 - 巴雷特狙击步枪 - : 单点射击! * */
参考链接:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具