- 多态的介绍
- 方法的多态
- 对象的多态
- 多态的细节
- 动态绑定机制
- 多态数组
- 多态参数
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承的基础之上的。
多态分为方法的多态和对象的多态,其中对象的多态是多态的核心。
三、方法的多态方法的多态体现在重写和重载上。也就是说,重写和重载都属于多态,它们都是多态的一种表现形式。
package com.javaploy;
public class Functionploy {
public static void main(String[] args) {
B b = new B();
b.sum(1,2,3);
b.sum(1,2);
A a = new A();
a.say();
b.say();
}
}
class A{
public void say(){
System.out.println("Class A is be used");
}
}
class B extends A{
public int sum(int a, int b, int c){
return a + b + c;
}
public int sum(int a, int b){
return a + b;
}
public void say(){
System.out.println("Class B is be used");
}
}
比如上面这段代码中,sum方法和say方法,就都体现了多态。
四、对象的多态重要的几句话:
- 一个对象的编译类型和运行类型可以不一致。
Animal animal = new Dog(); animal的编译类型是Animal,运行类型是Dog。
- 编译类型在定义对象时,就确定了,不能改变。但是运行类型是可以变化的。
animal = new Cat(); 这时候,animal的编译类型还是Animal,但是运行类型已经变成了Cat。
- 编译类型看定义时,看=号的左边,运行类型看=号的右边。
例:
package com.javaploy.objectploy;
public class Animal {
public void Cry(){
System.out.println("Animal is Crying");
}
}
class Dog extends Animal{
public void Cry() {
System.out.println("Dog is Crying");
}
}
class Cat extends Animal{
public void Cry() {
System.out.println("Cat is Crying");
}
}
package com.javaploy.objectploy;
public class PloyObject {
public static void main(String[] args) {
Animal animal = new Dog();
animal.Cry();
animal = new Cat();
animal.Cry();
}
}
输出结果为:
Dog is Crying
Cat is Crying
这里面,animal对象的编译类型一直是Animal,但是运行类型从Dog变成了Cat。
五、多态的细节-
多态的前提是:两个对象(类)存在继承关系
-
多态的向上转型 关于向上转型:
- 本质:父类的引用指向了子类的对象
- 语法:父类类型 引用名 = new 子类类型();
- 特点:编译类型看左边,运行类型看右边。 可以调用父类中的所有成员(需遵守访问权限) 不能调用子类中的特有成员(因为虽然运行类型是子类,但是能不能调用某个类成员,是在编译阶段,由编译器决定的,它的编译类型是父类,父类中没有子类特有的那个属性或方法,所以调不了。但如果调用子类中重写父类的方法,是可以调的,因为编译的时候,编译器找到了这个类,然后找的时候,还是会先从子类开始找。那么如果现在就想调用子类特有的成员,就需要向下转型。例如Cat cat = (Cat) animal;)。
-
多态的向下转型
- 语法:子类类型 引用名 = (子类类型) 父类引用;
- 只能强转父类的引用,不能强转父类的对象。
- 要求父类的引用必须指向的是当前目标类型的对象。
这句话怎么理解? 比如: Animal animal = new Cat(); 这时候,父类的引用指向的对象是Cat。 Cat cat = (Cat) animal; //正确 Dog dog = (Dog) animal; //错误
- 当向下转型后,可以调用子类类型中所有的成员。
-
调用属性,属性的值看编译类型。
-
instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型。
- 动态绑定机制
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定。
- 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。
看一段代码:
package com.javaDynamicBinging;
public class dynamicBanding {
public static void main(String[] args) {
A a = new B();
System.out.println(a.sum());
System.out.println(a.sum1());
}
}
class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i = 20;
public int sum(){
return i + 20;
}
public int getI(){
return i;
}
public int sum1(){
return i + 10;
}
}
上面这段代码,输出40和30。 如果把B类中的sum()方法去除,那么又会输出什么?
当B类中的sum()方法没有了之后,a.sum()自然而然的会去找其父类A的sum()方法。
结果发现里面又调用了getI()方法,这时候,由于B类和A类都有getI()方法,那么究竟调用哪一个?
这时候就用到了动态绑定机制,方法会和运行类型绑定,那么理所应当,调用B类中的getI()方法。
又因为属性不进行动态绑定,这时候方法在B类中,也就直接调用的B类的i的值。
所以输出30和30。
七、多态数组
多态数组:数组的定义类型为父类类型,里面保存的实际元素类型为子类类型。
比如有这样一道题目要求编写多态数组代码,创建一个Peroson父类,Student和Teacher子类。并将一个Person类对象和两个Student类对象以及两个Teacher类对象,一个五个元素同一放入数组中,并调用各自的say()方法。
package com.ployarr;
public class Javaployarr {
public static void main(String[] args) {
//这里创建了父类的数组,所有数组内可以放Person类,以及它的子类。
Person[] persons = new Person[5];
persons[0] = new Person("jack", 29);
persons[1] = new Student("lilei", 12, 90);
persons[2] = new Student("wang", 13, 92);
persons[3] = new Teacher("Hong", 32, 10000);
persons[4] = new Teacher("Bing", 30, 12000);
//循环遍历多态数组
for (int i = 0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?