1. 多态的概念和补充
1.1. 对象具有两种类型
编译类型: 声明对象变量的类型
运行类型: 对象的真实类型
编译类型必须是运行类型的父类或同类
当编译类型和运行类型不同的时候, 就产生多态所谓的多态其实是对象可以具有多种形态,
对象可以存在不同的形式.示例:
如下所示, 父类 SuperClass 定义的对象, 可以接收其子类实例化的对象
此时, 多态就产生了.public class SuperClass{...} public class SubClass01 extends SuperClass{...} public class SubClass02 extends SuperClass{...} public class Demo{ public static void main(String args[]){ SuperClass sp = new SubClass01(); SuperClass sp = new SubClass02(); } }
1.2. 多态的前提:
- 继承关系, 强调的是父类和子类间的关系
- 实现关系, 强调的是接口和实现类的关系
- 备注:
在实际应用的时候, 多态一般用于接口和实现类.
1.3. 多态的特点:
把子类对象赋给父类变量, 在运行时期会表现出具体的子类特征
1.4. 多态的好处:
把不同的子类对象都当做父类类型来看,
可以屏蔽不同子类对象之间的实现差异,
从而写出通用的代码达到通用编程,
以适应不断变化的需求, 减少方法的重载.
2. 多态方法调用的问题:
前提: 必须存在多态
2.1. 情况1: 若方法只存在于父类中, 在子类不存在
结果: 调用时是对父类方法进行调用.
原因:
若在子类中不存在方法, 则会去父类中寻找继承过来的方法.
类似于 js 中的原型链, 在原型链上逐级查找.public class SuperClass{ public void test(){ System.out.println("test in SuperClass"); } } public class SubClass extends SuperClass{ } public class TestDemo{ public static void main(String args[]){ SuperClass sp = new SubClass(); sp.test(); } }
2.2. 情况2: 若方法只存在于子类中, 在父类不存在
结果: 编译时报错.
原因:
编译时会先在编译类型中寻找是否存在对应方法
若不存在对应方法, 编译会报错.
因为多态主要用于接口中, 父类提供接口, 子类派生,
若接口本身就不存在, 则编译会报错.public class SuperClass{ } public class SubClass extends SuperClass{ public void test(){ System.out.println("test in SubClass"); } } public class TestDemo{ public static void main(String args[]){ SuperClass sp = new SubClass(); sp.test(); } }
2.3. 情况3: 若方法存在于父类中, 在子类也存在
- 结果: 调用时会调用子类的方法.
- 原因:
多态产生, 优先调用子类中的方法.public class SuperClass{ public void test(){ System.out.println("test in SuperClass"); } } public class SubClass extends SuperClass{ public void test(){ System.out.println("test in SubClass"); } } public class TestDemo{ public static void main(String args[]){ SuperClass sp = new SubClass(); sp.test(); } }
2.4. 情况4: 若方法存在于父类中, 在子类也存在, 但都是静态方法
- 结果: 调用时会调用父类的方法.
- 原因:
静态方法调用实际上时用类来调用,
因此若用对象来调用, 调用时是用对象的编译类型来调用.public class SuperClass{ public void test(){ System.out.println("test in SuperClass"); } } public class SubClass extends SuperClass{ public void test(){ System.out.println("test in SubClass"); } } public class TestDemo{ public static void main(String args[]){ SuperClass sp = new SubClass(); sp.test(); } }
3. 字段不存在多态
3.1. 字段的调用
通过对象调用字段, 在编译时期就已经决定了调用哪一块内存空间的数据.
字段不存在覆盖的概念, 不具有多态的特征,
若子类父类具有同名字段, 则调用的字段根据其编译类型来决定,
即若编译类型为父类, 则调用父类的该字段, 反之则调用子类的字段.
3.2. 字段的存储
当子类和父类存在相同的字段的时候, 无论修饰符是什么,
都会在各自的内存空间中存储数据.