面向对象
面向对象的特征有三方面:
- Encapsulation (封装)
- Inheritence (继承)
- Polymorphism (多态)
继承
Java 只支持单继承,但可以实现多个接口
abstract class VS interface
| abstract class | interface | |
|---|---|---|
| 设计目的 | 在代码实现方面发挥作用,可以实现代码的重用 | 在系统框架设计方法发挥作用,主要定义模块之间的通信 |
| 初始化块 | 可以 | 不可以 |
| 构造方法 | 可以 但是不能用于创建对象,而是让子类调用 |
不可以 |
| 方法 | 没有限制,可以同时包含抽象和非抽象的方法 | 只能并且默认是 public abstract 方法 |
| 属性 | 静态常量属性和普通属性 | 只能并且默认是 public static final 属性 |
| 继承/实现 | 一个类是只能继承一个抽象类 | 一个类可以可以实现多个接口 一个接口不能实现另一个接口,但它可以继承多个其他接口。 |
| 方法实现 | 重写父类的抽象方法或者将子类定义为抽象类 | 必须要实现接口声明的所有方法 |
示例:
1 | interface A {} |
多态
Java 中实现多态的机制是:
- Override(覆盖)
- Overload(重载)
对比:
| Override(覆盖) | Overloade(重载) | |
|---|---|---|
| Scope | 父类与子类之间多态性的一种表现 | 一个类中多态性的一种表现 |
| 基本概念 | 子类中定义的方法与其父类中的方法有相同的名称、参数列表、返回值类型 | 一个类中具有相同方法名的方法的参数列表在顺序、个数、类型上存在不同 (与方法的返回值类型无关) |
Override (覆盖)
- 方法的参数签名和返回值类型必须相同,访问控制修饰符可以不同,但是子类方法不能缩小父类方法的访问权限。
- 子类方法抛出的异常必须和父类方法抛出的异常相同,或者是父类方法抛出的异常类的子类。
- 父类的静态方法是不能被子类覆盖为非静态方法。父类的非静态方法不能被子类覆盖为静态方法。
- 子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法。区别:运行时,JVM 把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。
- 父类的私有方法不能被覆盖
- 父类的非抽象方法可以被覆盖为抽象方法
JVM 实现
原则:“编译看左边,运行看右边”,即:在编译时,看引用类型的类是否有此方法;在运行时,看对象所在的类是否有调用的方法。
1) 对于一个引用类型的变量,Java编译器按照它声明的类型来处理。
1 | Base base = new Sub(); |
编译出错,编译器认为 base 是 Base 类型的引用变量,Base 类没有 subMethod() 方法。必须使用强制转换。
1 | (Sub)(base).subMethod(); |
2) 对于一个引用类型的变量,运行时 JVM 按照它实际引用的对象来处理。
1 | Base base = new Base(); |
编译通过,但是运行时抛出 ClassCastException。在运行时,子类的引用类型变量可以转换为父类的引用类型,而相反的过程却不可以。
3) 在运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,JVM 采用以下的绑定规则。
- 实例方法与引用变量实际引用的对象的方法绑定,即动态绑定。
- 静态方法与引用变量所声明的类型的方法绑定,即静态绑定。 编译阶段即绑定完成。
- 成员变量(静态变量和实例变量) 与引用类型所声明的类型的成员变量绑定。静态绑定。
例子:
1 | public class Base { |
结果:
1 | Sub.hello |
Overload(重载)
如果在一个类中定义了多个重载的方法,只需根据所传参数列表的不同来调用不同的重载方法。