一、封装
1. 程序存在的问题
数据无法保证安全性,同时无法保证数据有效性。
2. 封装访问修饰
private:私有的,被 private 修饰的内容仅能在本类内部访问public:公开的,任意位置都可以访问
3. 为私有属性提供 get /set 方法
set 方法:给属性赋值
// set方法,属性名首字母大写 public void set属性名(数据类型 变量名){ this.属性名 = 变量名; }注意:形参的数据类型,要和被赋值的属性类型保持一致;可以在 set 方法内部做数据合法性校验。
get 方法:获取属性的值
// get方法,属性名首字母大写 public 数据类型 get属性名(){ return this.属性名; // this 可以省略 }返回值类型和被访问的属性数据类型保持一致。
4. 封装小结
- 属性私有化:使用
private修饰成员属性 - 对外提供公开的 get/set 方法,完成赋值与取值
- 常在 set 方法中增加业务逻辑,校验传入数据是否合法
二、继承
继承体现类与类之间is‑a的关系。 例:水杯是一种容器;狗是一种动物;手机是一种电子产品。
1. 继承概念
- 子类
extends父类,语法:
class 子类 extends 父类{ }- 子类可以直接复用父类中非私有属性与方法
- 继承是客观存在的 is‑a 关系,不要强行使用继承
2. 继承好处
提高代码复用性,提升代码扩展性。
3. 方法重写 override
子类定义和父类签名完全一致的方法。
重写要求
- 方法名、形参列表、返回值类型和父类保持一致
- 子类访问修饰符与父类相同,或者访问权限更宽泛
使用规则
使用子类对象调用方法,如果子类重写了父类方法,优先执行子类重写后的方法。
⚠️注意
- 方法名、参数列表相同,返回值不同:编译报错,不构成重写
- 方法名相同,参数列表不同:属于方法重载 overload,不是重写
使用场景
父类原有方法逻辑,无法满足子类业务需求,子类对方法进行重新实现。
📌面试题:overload 和 override 的区别
- Overload(方法重载)方法名相同,形参列表不同(个数、顺序、类型);和返回值、访问修饰符、异常无关。
- Override(方法重写)子类方法名、参数列表、返回值和父类完全一致;子类访问权限不能比父类更严格。
4. 父类与子类设计思路
父类抽取多个子类的共性属性和行为;父类偏向通用抽象,子类偏向具体特殊。开发中抽取多个类的公共逻辑作为父类。
5. Java 继承特点
- Java 为单继承:一个类只能有一个直接父类,支持多级间接继承。
- 一个父类可以拥有多个子类。
6. 子类可以继承父类哪些内容(面试重点)
- 构造方法不能被继承
- 构造方法名必须和本类类名一致,子类和父类类名不同
- 子类会新增自己独有的属性,父类构造方法无法适配子类。
- 属性、普通成员方法能否继承,取决于访问修饰符
表格
| 修饰符 | 本类 | 同包 | 不同包子类 | 不同包无关类 |
|---|---|---|---|---|
| public | ✅ | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ✅ | ❌ |
| default (默认不写) | ✅ | ✅ | ❌ | ❌ |
| private | ✅ | ❌ | ❌ | ❌ |
总结:
private:不能继承- default:同包子类可以继承
- protected:同包、不同包子类均可继承
- public:所有子类均可继承
补充:属性、成员方法、构造器可以使用 4 种访问修饰符;类只能使用 public 和 default。
7. super 关键字(开发重点)
① super. 访问父类成员
super.属性名:访问父类的成员属性super.方法名(实参):调用父类的成员方法
使用位置:子类普通成员方法、子类构造方法内。
② super () /super (实参)
- 写在子类构造方法第一行有效语句,用来调用父类构造方法。
- 如果子类构造方法没有手动写
super(),JVM 会默认补无参super()。 super()和this()不能同时出现在同一个构造方法第一行。- 如果构造第一行写
this(),JVM 不会自动补super(),会顺着 this 指向的构造方法去找 super。
8. 继承关系下对象创建过程(难点)
new 子类对象时,JVM 会同时创建配套父类对象,该父类对象仅供子类内部使用。
执行流程:
- new 分配内存空间(子类 + 父类),所有属性赋默认初始值
- 进入子类构造方法,第一行执行
super()/super(实参)- 执行父类属性初始化
- 执行父类构造方法剩余代码
- super 执行完毕,回到子类构造
- 执行子类属性初始化
- 执行子类构造剩余业务代码
编译器会把属性初始化代码,移动到对应构造方法中,放在 super 之后,构造其余代码之前。
三、多态
1. 概念
父类类型引用指向子类对象
父类类型 引用名 = new 子类类型();- 编译看左边:编译阶段,只能调用父类中声明的属性和方法;父类没有则编译报错。
- 运行看右边:运行时,如果子类重写了父类方法,优先执行子类重写方法;没有重写执行父类原始方法。
2. 引用类型转换
(1)向上转型(自动,多态):子类引用赋值给父类引用
小类型 → 大类型,直接赋值,就是多态写法
Animal a = new Dog();(2)向下转型(强制类型转换):父类引用赋值给子类引用
大类型 → 小类型,必须强转
子类类名 引用变量 = (子类类名)父类引用;示例:
Animal a = new Dog(); Dog d = (Dog) a;注意:
- 如果实际对象类型和强转目标类型一致:编译运行全部正常。
- 如果实际对象和目标类型不一致:编译通过,运行抛出
ClassCastException类型转换异常。- 两个类没有继承关系,不能强转,直接编译报错。
3. instanceof 关键字
引用变量 instanceof 类名- 作用:判断引用指向的实际对象,是否属于该类或其子类;返回 true/false。
- 开发场景:向下强转之前,先用 instanceof 做判断,规避
ClassCastException类型转换异常。
4. 多态的三种应用场景
- 数组:数组声明为父类类型,数组中可以存放本类以及所有子类对象
Animal[] as = new Animal[3]; as[0] = new Dog(); as[1] = new Cat(); as[2] = new Dog();- 方法形参:形参写父类类型,可以接收本类以及全部子类对象。
- 方法返回值:返回值写父类类型,可以返回本类或者任意子类对象。
5. 多态好处
统一管理多个子类对象,面向父类编程,降低代码耦合。