面向对象和面向过程
面向过程(POP):面向过程是具体到每一个行为,按顺序执行
面向对象(OOP):面向对象是一种编程思想,将现实世界中的事物抽象为对象,每个对象既包含数据(属性)也包含操作数据的方法(行为)
类与对象
面向对象编程最基础的是对象,类是所有对象的抽象模板,对象是类的一个具体实例
成员变量和局部变量
成员变量是对象的属性,伴随对象出生与消亡,有默认值,可跨方法访问;局部变量是方法的临时工,随方法生灭,必须初始化,只能在本方法内干活
命名冲突与就近原则
当成员变量与局部变量同名时,局部变量优先(就近原则),如需访问成员变量,需用this(实例)或类名(静态)加以区分
this关键字
用来指代当前类的实例对象,用于调用当前类的属性和方法
静态代码块
仅在类被加载时加载一次
代码块执行顺序
代码块、静态代码块、父子类构造器执行顺序
- 父类的静态代码块
- 子类的静态代码块
- 父类的代码块
- 父类的构造器
- 子类的代码块
- 子类的构造器
类访问权限
| 访问修饰符 | 同类内 | 同包内 | 子类(不同包) | 任何地方 |
|---|---|---|---|---|
| private | √ | × | × | × |
| 默认(无修饰符) | √ | √ | × | × |
| protected | √ | √ | √ | × |
| public | √ | √ | √ | √ |
方法重写和重载
重载是同一个类中的横向扩展,重写是父子类之间的纵向覆盖
重载规则
- 方法名相同
- 参数列表不同(个数、类型、顺序至少一项不同)
- 返回值类型可以不同
- 访问修饰符可以不同
- 异常声明可以不同
- 静态方法可以重载
重写规则
前提是继承了父类
- 父子类方法名相同
- 父子类参数列表相同
- 子类方法返回值和父类方法返回值相同或是其子类
- 子类方法访问权限不能小于父类
封装
保证数据安全性,把数据(属性)和操作数据的方法(行为)捆绑在一起,并对外隐藏内部实现细节,只暴露必要的访问接口
继承
允许一个类(子类)基于另一个类(父类)来构建,复用父类的属性和方法,并在此基础上扩展或改写自己的特有行为
误区1:子类继承了父类的所有内容
private 成员、构造方法、静态初始化块都不被继承。子类只能通过父类的 public/protected 方法间接访问 private 数据
误区2:继承是为了复用代码(唯一目的)
继承更重要的目的是建立类型体系,实现多态。List 接口有 ArrayList、LinkedList 等多个实现,它们共用一个 List 类型,这才是继承的核心价值
误区3:继承层次越深越好
深层继承链会导致代码难以理解和维护。通常建议继承深度不超过 3 层,过深时应考虑使用组合或接口
多态
多态就是同一个行为(方法调用)在不同对象身上表现出不同的形态。它建立在封装和继承的基础之上,是让代码具备扩展性和灵活性的魔法
多态的三个必要条件
- 继承:存在父子类关系(或接口实现关系)
- 重写:子类重写了父类的方法
- 父类引用指向子类对象
Parent p = new Child()
抽象
核心思想:只关注“做什么”,不关注“怎么做”,它让代码面向“概念”编程,而不是面向“实现”编程,是软件具备可扩展性和可维护性的根基,没有抽象,就没有真正的面向对象
抽象方法所在的类,必须定义为抽象类,抽象类不能被实例化,只能实例化其子类
接口
接口(Interface)是面向对象编程中实现抽象和多态的核心工具,它定义了一组行为规范或契约,规定了实现类必须具备哪些能力,但不关心这些能力具体怎么实现,解决了代码的解耦合问题
接口和抽象类的区别
- 关键字不同(abstract,interface)
- 抽象类可以包含非抽象方法,接口中全是抽象方法
- 具体化方法不同:接口通过实现类,抽象类通过继承
- 抽象类单继承,接口多实现
- 设计目的不同:抽象类是代码复用,接口是行为规范
设计层面的本质区别
- 抽象类是
从下往上的复用,接口是从上往下的约束 - 抽象类描述
是什么,接口描述能做什么
接口能替代抽象类吗?
不能。 根本原因:
- 接口不能有实例变量(无法保存对象状态)
- 接口的 default 方法如果有冲突(多继承的菱形问题),需要子类手动解决
- 抽象类可以控制访问权限(protected 给子类用,接口所有方法默认 public)
包装类
| 基本数据类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
异常
