目录
多态
多态是面向对象编程中的一个重要特点,它允许通过父类类型的引用变量来引用子类对象,并在运行时根据实际对象的类型来确定调用哪个方法。即一个对象可以根据不同的情况表现出多种形态。
通过多态,我们可以利用父类类型的引用变量来指向子类对象,并根据实际对象的类型调用对应的方法。这样可以在不修改现有代码的情况下,动态地切换和扩展对象的行为。
多态的特点和优势:
- 可替换性:子类对象可以随时替代父类对象,向上转型。
- 可扩展性:通过添加新的子类,可以扩展系统的功能。
- 接口统一性:可以通过父类类型的引用访问子类对象的方法,统一对象的接口。
- 代码的灵活性和可维护性:通过多态,可以将代码编写成通用的、松耦合的形式,提高代码的可维护性。
实现原理
要了解多态的实现原理,需要先了解两个概念:动态绑定和虚拟方法调用。
1 动态绑定
动态绑定(Dynamic Binding):指的是在编译时,Java 编译器只能知道变量的声明类型,而无法确定其实际的对象类型。而在运行时,Java 虚拟机(JVM)会通过动态绑定来解析实际对象的类型。这意味着,编译器会推迟方法的绑定(即方法的具体调用)到运行时。正是这种动态绑定机制,使得多态成为可能。
2 虚拟方法调用
虚拟方法调用(Virtual Method Invocation):在 Java 中,所有的非私有、非静态和非 final 方法都是被隐式地指定为虚拟方法。虚拟方法调用是在运行时根据实际对象的类型来确定要调用的方法的机制。当通过父类类型的引用变量调用被子类重写的方法时,虚拟机会根据实际对象的类型来确定要调用的方法版本,而不是根据引用变量的声明类型。
3 实现原理综述
所以,多态的实现原理主要是依靠“动态绑定”和“虚拟方法调用”,它的实现流程如下:
- 创建父类类型的引用变量,并将其赋值为子类对象。
- 在运行时,通过动态绑定确定引用变量所指向的实际对象的类型。
- 根据实际对象的类型,调用相应的方法版本。
泛型擦除
泛型:将类型作为参数,将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型)
Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。看下面代码
可以看到 ArrayList<Integer>和 ArrayList<string>的原始类型是相同,在编译成字节码文件后都会变成 List ,JVM看到的只有 List,看不到泛型信息,这就是泛型的类型擦除。在看下面这段代码
可以看到通过反射进行 add 操作,ArrayList<Integer>竟然可以存储字符串,这是因为在反射就是在运行期调用的 add方法,在运行期泛型信息已经被擦除。
既然存在类型擦除,那么ava是如何保证在 ArrayList<Integer>添加字符串会报错呢?
Java编译器是通过先检查代码中泛型的类型,然后在进行类型擦除,再进行编译。