目录
面向对象
1.什么是面向对象?
2.面向对象的特点有哪些?
3.什么是对象?
4.什么是类?
5.什么是构造方法?
6.构造方法的特性有哪些?
封装
1.什么是封装?
2.封装有哪些特点?
数据隐藏
接口简化
可维护性增强
复用性提高
3.为什么需要使用封装?
继承
1.什么是继承?
2.继承有哪些特点?
3.为什么要继承?
方法的重写
1.什么是方法的重写?
2.方法重写的要求是什么?
3.什么是重载?
4.重载的特点是什么?
5.重写和重载的区别是什么?
6.重写的设计原则是什么?
多态
1.什么是多态?
2.多态有哪些特点?
多态的缺陷:
3.为什么要使用多态?
4.实现多态的条件有哪些?
5.什么是多态中的向上转型和向下转型?
面向对象
1.什么是面向对象?
面向对象是解决问题的一种思想,主要是依靠对象之间的交互完成一件事情。
面向对象(Object-Oriented Programming, OOP)将现实世界中的事物抽象为具有状态(数据)和行为(功能)的对象,并通过对象之间的交互来设计和构建程序。
2.面向对象的特点有哪些?
面向对象的特点是:封装、继承和多态。
3.什么是对象?
定义:对象是现实世界中事物的抽象,是面向对象的基本单元,包含 状态(属性) 和 行为(方法)。
状态:举个例子,我现在创建了一个“学生”对象,这个对象他的年龄,性别,籍贯等等属于他的属性,也就是对象的状态(数据)。又或者说大家玩儿游戏,游戏中的角色的各种生命值,攻击力等等,这些属性属于“状态”。
行为:那么我这个学生或者某个游戏角色他们干了什么,这个属于我这个对象所执行的操作,比如他考试或者打怪。这就是用方法(函数)描述对象能执行的操作。
总的来说就是,它(对象),它中包含了(它的信息(属性),以及它要干什么(行为)。
4.什么是类?
定义:类是对象的模板(蓝图),定义了一类对象共有的属性和方法。
我们可以这样理解,类中其实就打包了这个对象的信息以及他要干什么。
那么我们就说对象是类的实例(Instance),通过 new
关键字创建。
//定义学生类
class Student{
String name; //属性
int age;
void study(){
System.out.println(name+"在学习");//状态
}
}
Scanner sc = new Student();
5.什么是构造方法?
定义:构造方法(Constructor)是类中的一种特殊方法,主要用于在创建对象时对对象进行初始化操作。
构造方法的主要作用是在创建对象时为对象的属性赋初始值。
如果我们使用构造方法,便可以初始化这个学生对象的属性。
// 构造方法,用于初始化学生对象的属性
public Student(String name, int age) {
this.name = name;
this.age = age;
完整示例:
class Student {
String name;
int age;
// 构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
void study() {
System.out.println(name + "在学习");
}
public static void main(String[] args) {
// 创建 Student 对象,调用构造方法进行初始化
Student stu = new Student("李四", 22);
stu.study();
}
}
6.构造方法的特性有哪些?
- 名字必须与类名相同
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并在对象的生命周期内只调用一次。(也就是说创建对象之后只能调用一次构造方法。)
- 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
封装
1.什么是封装?
封装(Encapsulation)是将数据(类的属性)和操作数据的方法(类的方法)封装在一个独立的类中,并通过访问修饰符控制外部对内部数据的访问,从而实现数据隐藏和接口控制。
类的使用者不需要知道类是如何实现的。实现的细节被封装并且对用户隐藏起来,这被称为类的封装。
2.封装有哪些特点?
(1)数据隐藏:通过访问控制(如私有属性)禁止外部直接操作数据,确保数据安全与完整性,仅允许类内方法交互。
(2)接口简化:提供公共方法作为外部交互接口,隐藏内部实现细节,降低使用复杂度,提升代码易读性。
(3)可维护性增强:内部实现修改不影响外部调用(只要接口不变),减少代码耦合,降低维护成本与风险。
(4)复用性提高:封装后的类作为独立模块,可重复应用于不同场景,避免重复开发,提升代码利用率。
下面我们来详细讲解:
数据隐藏
想象你有一个存钱罐,里面装着你的零花钱。这个存钱罐就像是一个被封装起来的东西,它有一个小口子,你只能通过这个口子把钱放进去或者拿出来。存钱罐里面具体有多少钱,外面的人是看不到的,这就相当于数据被隐藏起来了。只有你自己知道怎么去操作这个存钱罐(就像类里面的方法可以操作数据),别人没办法直接把手伸进去动你的钱,这样就能保证你钱的安全,不会被别人乱花。
接口简化
还是拿存钱罐来说,对于其他人来讲,他们不需要知道存钱罐内部的构造是什么样的,也不用管钱在里面是怎么摆放的。他们只需要知道,把钱从那个小口子放进去,存钱罐就能帮他们把钱存起来;想取钱的时候,从那个小口子把钱拿出来就行。这就好比类提供了公共的方法,外部的人只需要知道怎么使用这些方法,而不用去了解类内部是怎么实现这些功能的,这样使用起来就简单多了。
可维护性增强
假如你觉得现在这个存钱罐不太好用了,想换一个新的存钱罐。只要新存钱罐也有同样的小口子,能实现存钱和取钱的功能,那么对于那些用这个存钱罐存钱取钱的人来说,他们根本不需要做任何改变,还是像以前一样把钱放进去、拿出来就行。在编程里,这就相当于修改类的内部实现,只要公共的接口(方法)不变,外部的代码就不用跟着改,维护起来就很方便。
复用性提高
你可以想象存钱罐是一个很实用的东西,在不同的地方都能用到。比如在家里,你可以用它存零花钱;在学校,你也可以用它存一些买文具的钱。同样的道理,封装好的类就像这个存钱罐一样,可以在不同的程序或者代码场景中被重复使用,不用每次都重新去设计一个存钱罐(编写相同的代码),这样能节省很多时间和精力。
3.为什么需要使用封装?
我们使用封装,可以保证数据的安全性,方便我们操作类中的数据。
举个例子:你有一个“银行卡”盒子,里面的余额是秘密,外面不能直接看或改。但盒子提供了“查询余额”“存钱”“取钱”按钮,每次取钱时按钮会检查余额够不够,确保不会取出负数。这就是封装!
继承
1.什么是继承?
定义:子类(派生类)可以继承父类(基类)的属性和方法,实现代码复用,并可以扩展或重写父类功能。
继承(inheritance)机制:它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生的类叫派生类。
继承主要解决的问题是:共性的抽取,实现代码复用。
就比如说,我现在有个学生类,此为父类,大学生为父类中的(子类),他继承了学生类所具有的所有所有的属性和行为。
又或者说你爸爸会开车(定义一个 “人类” 类,里面有 “开车” 的方法),你作为儿子(子类),可以直接继承爸爸的 “开车” 能力,不用自己重新学。
同时,你还能自己新增能力,比如 “开赛车”(子类独有的方法),或者把 “开车” 升级(比如爸爸开车很慢,你开车很快,重写父类方法)。
我们需要注意的是:子类并不是父类的一个子集。实际上,一个子类通常比它的父类包含更多的信息和方法。
2.继承有哪些特点?
(1)代码复用
(2)方法重写(覆盖,Override)
(3)扩展性与封装性
(4)在 Java 中一个类只能直接继承一个父类。
3.为什么要继承?
当然是为了实现共性抽取,代码的复用啦!同时支持在父类基础上扩展或修改功能,
继承使得你可以定义一个通用的类(父类),之后可以扩充为一个更加特定的类(子类)。
当子类继承父类之后,一定要先帮助父类进行构造,然后再构造子类自己。只能在子类当中,调用父类的构造方法。(注意:只能在子类当中,调用父类的构造方法!)
方法的重写
1.什么是方法的重写?
方法重写(Method Overriding)是面向对象编程里的一个关键特性,其指的是在子类中对父类里已有的方法进行重新定义。重写后的方法名、参数列表和返回类型与父类中的方法相同,不过方法体内容有所不同。
所以,方法的重写也被称为覆盖,重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
打个比方说,假设我目前定义了一个学生类和大学生类,大学生类是学生类的子类,我现在想更改大学生类,这时就可以使用方法的重写。通过方法重写,大学生(子类)能够重新定义从学生(父类)继承而来的方法,从而让大学生(子类)展现出和学生(父类)不一样的行为。
2.方法重写的要求是什么?
(1)方法名必须相同
(2)参数列表必须相同(类型,个数,顺序)
(3)返回值必须相同
(4)必须基于继承关系
(5)使用 @Override
注解标识重写的方法
我们需要注意的是,当我们想使用方法的重写,那么就必须遵守规则:
(1)被private修饰的方法不能进行重写;
(2)被static修饰的方法不能进行重写;
(3)被final修饰的方法不能进行重写(密封方法);
(4)子类重写父类方法时,访问修饰限定符不能比父类被重写方法的权限更严格(即范围更小),但可以更宽松(即范围更大)
-
若父类方法是
private
:
因private
权限最小(仅类内可见),子类无法访问该方法,不能重写。 -
若父类方法是默认权限(无修饰符,包内可见):
子类若与父类在同一包中,重写时可使用默认权限或更宽松的protected
、public
;若不在同一包中,因默认权限对子类不可见,不能使用默认权限重写,需选择protected
或public
(权限更宽泛)。 -
若父类方法是
protected
:
子类重写时,可选择protected
或更宽松的public
,但不能使用默认权限或private
(权限更严格)。 -
若父类方法是
public
:
因public
权限最大,子类重写时必须保持public
,不能缩小为protected
、默认权限或private
。
(5)方法的返回值之前可以不同,但是必须是父子类关系(协变返回类型)
(6)构造方法不能发生重写
3.什么是重载?
重载(Overload)是指在同一个类中定义多个方法(行为),这些方法名字相同,不过参数列表不同。
重载的目的是让类能够根据不同的参数类型或参数数量来执行不同的操作。
重载就是你在一个类中,让多个方法共用一个名字,但根据参数(比如数量、类型)的不同,执行不同的操作。
举个例子,假如说我们在餐厅中,有个“做面条”的操作,做面条是方法名,如果顾客想吃素面,就只需要“面条”这一个参数;假如顾客想吃鸡蛋面,就需要“鸡蛋”+“面条”这两个参数。两个同样都是“做面条”的方法名,但由于参数不同(一个参数是面条,另一个是面条+鸡蛋),这就是重载。
4.重载的特点是什么?
(1)发生在同一个类中:同一个类里可以定义多个同名方法。
(2)参数列表不同:参数的类型、数量或者顺序不一样。
(3)编译时确定调用:编译器会根据调用时传入的参数来决定调用哪个方法
5.重写和重载的区别是什么?
- 重写:发生在子类和父类之间,方法签名相同,用于实现多态,运行时确定调用的方法。
- 重载:发生在同一个类中,方法名相同但参数列表不同,用于提供多种不同的调用方式,编译时确定调用的方法。
方法的重载是一个类的多态性表现,而方法的重写是子类对父类的一种多态性表现。
在重载中,我们必须修改参数列表、返回类型、访问修饰限定符。
区别点 | 重写(override) | 重载(overload) |
参数列表 | 一定不能修改 | 必须修改 |
返回类型 | 一定不能修改(除非可以构成父子关系) | 可以修改 |
访问限定符 | 一定不能做更严格的限制(可以降低限制) | 可以修改 |
6.重写的设计原则是什么?
- 静态绑定:也称为前期绑定(早绑定),在编译时,根据用户所传递实参类型就确定了具体调用哪个方法,典型的代表就是函数重载。
- 动态绑定:也称为后期绑定(婉绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定调用哪个类的方法,一般用于重写。
静态绑定一般发生在编译阶段,根据变量的声明类型确定调用的方法,由编译器直接生成对应的方法调用地址。一般我们在同一类里的方法重载会使用。
我们来看一个例子,假如你有一个同学,他既是程序员(声明类型),也是游戏高手(实际身份)。如果你叫“程序员来修电脑”(调用方法),不管他是不是程序员,编译器只会让他使用“程序员修电脑”的方法,不会管它是不是游戏高手。
那么动态绑定,一般发生在运行阶段,程序根据对象的实际类型,决定调用哪个方法。典型的代表就是方法的重写。
比如说,你说“我是一个人”(父类声明),但实际上你可能是“学生”、“老师”、“医生”(子类对象),当你需要工作时(调用重写的方法),你到底是学生写作业、老师讲课,还是医生看病,取决于你是谁。
所以,如果我们是 静态绑定 ,就要看 编译时 变量声明的类型。
当然,如果我们是 动态绑定 , 就要看 运行时 对象实际的类型。
多态
1.什么是多态?
定义:同一操作(如方法调用)在不同对象上表现的行为。
用通俗的话来讲,就是“同样的指令,不同的对象有不同的反应”。
举个例子,我们现在定义了一个动物类,猫、都是这个动物类的子类,他们都有会叫的“方法”,那么我们使用多态的话,就可以让不管是猫还是狗,都可以通过动物类来让这些子类使用它们的“方法(会叫)”,代码更简单,并且能实现代码复用。
2.多态有哪些特点?
多态的优点:
(1)能够降低代码的 "圈复杂度", 避免使用大量的 if - else
(2)可扩展能力更强
什么叫 "圈复杂度" ?
多态的缺陷:
3.为什么要使用多态?
我们使用多态,就可以在同一个接口下,统一处理不同的对象,并且减少大量的if-else的使用。
在面向对象编程中,多态是静态绑定(编译时绑定)和动态绑定(运行时绑定)的结合体。
所以多态能同时满足 “代码复用”(静态多态简化重载逻辑)和 “灵活扩展”(动态多态支持子类新增行为)的需求。
多态的本质是 “通过抽象接口隔离变化”:将不变的逻辑(父类定义的通用规则)与变化的实现(子类的具体行为)分离,使代码更易维护、扩展和复用。
当需要新增功能(如子类)时,只需定义新的子类并实现父类接口 / 方法,无需修改已有调用逻辑。
通过多态,可以将现实世界中的复杂对象抽象为统一模型(如 “动物”“图形”),忽略具体细节,聚焦共性行为,使代码更贴近真实场景的逻辑。
多态允许用自然语言中的 “泛化” 概念(如 “所有动物都会叫”)来设计程序,而非针对每个具体类型(“狗会叫、猫会叫”)编写重复逻辑,代码更易理解和维护。
使用多态我们就无需显式将子类对象转换为具体类型即可调用其重写的方法(通过父类引用直接调用),避免了大量冗余的类型检查和强制转换。
4.实现多态的条件有哪些?
(1)必须在继承体系下
(2)子类必须要对父类中的方法进行重写
(3)通过父类的引用调用重写的方法
5.什么是多态中的向上转型和向下转型?
向上转型是多态的实现基础,而向下转型是多态的补充手段。
多态依赖向上转型实现动态绑定,通过向下转型扩展功能。
向下转型: 将父类引用还原成子类对象。
举个例子:我们把 “大学生”(子类)看作 “学生”(父类),用 “学生” 的身份活动。此时能调用重写后的 “考试”(子类实现的考试形式)。但 “大学生特有的技能,用‘学生’身份(向上转型后)就用不出来”,(向上转型后,它只 “暴露” 父类的功能。)比如 “大学生实习” 这个技能,因为 “学生” 这个身份(父类)没定义这个功能。如果想使用 “实习”,就得向下转型把 “学生” 再转回 “大学生”(且得先确认这个 “学生” 本质上是 “大学生”)。
总结:
- 向上转型:把子类当父类用,隐藏子类特有的功能,用统一的 “大身份” 活动。
- 向下转型:把父类转回子类,但得先确认它 “本质” 是这个子类,才能用子类特有的功能。