JAVA三大特性之多态

多态

多态的概念

多态的本质是:一个程序中同名的不同方法。在面向对象的程序设计中,多态主要有以下三种方式来实现。

  • 通过子类对父类方法的覆盖来实现多态
  • 通过一个类中方法的重载来实现多态
  • 通过将子类的对象作为父类的对象实现多态。

覆盖的概念我们在前面以及介绍了,接下来我们简单阐述下何为重载

  • 重载是指一个类里面(包括父类的方法)存在方法名相同,但是参数不一样的方法,参数不一样可以是不同的参数个数类型或顺序
  • 如果仅仅是修饰符、返回值、throw的异常 不同,那么这是2个相同的方法

我们重点阐述第三种实现方法,即通过将子类的对象作为父类的对象实现多态

把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,父亲的行为像儿子,而不是儿子的行为像父亲。(这句话是我理解第三种方法的关键,请仔细阅读理解)

继承是面向对象语言中一个代码复用的机制,简单说就是子类继承了父类中的非私有属性和可以继承的方法,然后子类可以继续扩展自己的属性及方法。

对象的引用型变量是具有多态性的,因为一个引用型变量可以指向不同形式的对象,即:子类对象作为父类对象来使用。在这里涉及到了向上转型和向下转型。

向上转型

    子类对象转为父类,父类可以是接口。公式:Father f = new Son(); Father是父类或接口,Son是子类。

向下转型

父类对象转为子类。公式:Son s = (Son) f;

在向上转型的时候我们可以直接转,但是在向下转型的时候我们必须强制类型转换。并且,如案例中所述,该父类必须实际指向了一个子类对象才可强制类型向下转型。若Father f = new Father()那么不可以转换,运行会报错。

对于多态,我们先举一个例子。在一个单位中,有职工employee,职工中又有少数是管理者manager,管理者中又有一部分是领导。若小明是管理者manager类的对象,他也可以被看做是employee的对象,即他也可以被看做是一个职工,他同时具备着职工的所有属性。

//定义一个父类
class Employee
{
	String name;
	int age;
	float salary;
	
	Employee(){};
	
	Employee(String name,int age,float sal)
	{
		this.name=name;
		this.age=age;
		this.salary=sal;				
	}
	String getInfo()
	{
		return "职工姓名:"+name+"年龄:"+age+"工资:"+salary;
	}
//定义一个子类
class Manager extends Employee
{
	float allowance;
	Manager(String name,int age,float sal,float aa)
	{
		this.name=name;
		this.age=age;
		this.salary=sal;
		allowance=aa;
	}
//测试
public static void main(String[] args) {
		Employee emp1=new Employee("小明",23, 1000);   //emp1是Employee的对象
        System.out.println(emp1.getInfo());
        
        Employee emp2=new Manager("小明",23, 1000,5000); //注意此处emp2是Manager类的对象
        System.out.println(emp2.getInfo());
	}

请添加图片描述

接下来我们再来看一个经典的多态讲解案例,代码如下:

class A {
    public String show(D d) {
        return ("A and D");
    }
    public String show(A a) {
        return ("A and A");
    }
class B extends A {
    public String show(B b) {
        return ("B and B");
    }
    public String show(A a) {
        return ("B and A");
    }
}
class C extends B {}
class D extends B {}
public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
 
        B b = new B();
        C c = new C();
        D d = new D();
 
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("--------------");
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("--------------");
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));
    }

这段代码的输出是啥呢?大家可以先分析分析,然后再看正确答案。

请添加图片描述

在分析结果之前,我们先来看相关的知识点概念:

  • 父类对象引用变量引用子类对象时,被引用对象的类型不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法

产生多态时候,各个方法调用的优先级顺序由高到低依次为:

this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)

我们来分析以下结果:

(1)System.out.println(“1–” + a1.show(b));

  	 首先a1是一个标准的A对象的引用变量,传入的参数为标准的 new B(),我们在A类的方法中找不到show(B b)的方法,接着
   去看A的超类是否有show(B b)的方法,发现A没有超类。那么去执行this.show((super)O),即A类中的show(A a)方
   法,所以输出为A and A

(2)System.out.println(“2–” + a1.show©);

  	同理,a1.show(c) C的父类是B,所以C也是A的子类,那么最后还是调用A类中的show(A a)方法,所以输出为A and A

(3)System.out.println(“3–” + a1.show(d));

  	这个没什么好疑惑的,直接就是调用A类中的show(D obj),所以输出为A and D

(4)System.out.println(“4–” + a2.show(b));

  	这个的结果输出就有点迷惑人了,小伙伴们会惊奇,为什么不是调用B类中的show(B b)方法输出B and B ?我们来解释
  下,a2是一个父类A的引用变量指向了一个子类B的对象,也就是说表面类型是A,实际类型是B。当我们调用方法
  的时候,首先从其表面类型里边寻找方法 show(B b)结果没有找到,那么按照调用优先级,我们最终会调用
  到this.show((super)O) 也就是说我们调用了A类中的show(A a)方法。按照上边所述的概念:当父类对象引用变量
  引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必
  须是在超类中定义过的,也就是说被子类覆盖的方法。在当前的表面类型中找到了该方法show(A a),并且在子类(B)中
  也覆盖了该方法,那么最终会调用实际类型(B类)中的该方法show(A a),所以输出B and A。

(5)System.out.println(“5–” + a2.show©);

  	这个分析和4中的保持一致

(6)System.out.println(“6–” + a2.show(d));

 	这个没什么疑问,在A类中找到了该方法show(D d),并且子类没有覆盖该方法,所以直接调用A类中的方法,输出A and D

(7)System.out.println(“7–” + b.show(b));

   	b.show(b)应该没什么疑问,会直接调用B类中的方法show(B b) 输出 B and B

(8)System.out.println(“8–” + b.show©);

 	根据方法调用优先级,最终会调用到B类中的方法show(B b) 输出 B and B

(9)System.out.println(“9–” + b.show(d));

 	根据方法调用优先级,最终会调用到A类中的方法show(D d) 输出 A and D

  	这是多态学习中的一个经典案例,我们要牢记方法之间的调用优先级,并且要分清楚表面类型和实际类型,
  以及区分子类中是否进行了方法的覆盖等知识点,这样才能做到条理清晰。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值