java中的多态

一、多态的来历

我们先来了解一个业务背景:请设计一个系统,描述主人喂养宠物的场景,首先在这个场景当中应该有“宠物对象”,宠物对象应该有一个吃的行为,另外还需要一个“主人对象”,主人对象应该有一个喂的行为,请看代码:

//宠物狗

public class Dog {
    String name;
    public Dog(String name){
        this.name = name;
    }
    //吃的行为
    public void eat(){
        System.out.println(this.name + "在啃肉骨头!");
    }
}

//主人

public class Master {
    //喂养行为
    public void feed(Dog dog){
        //主人喂养宠物,宠物就吃
        System.out.println("主人开始喂食儿");
        dog.eat();
        System.out.println("主人喂食儿完毕");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //创建狗对象
        Dog dog = new Dog("二哈");
        //创建主人对象
        Master master = new Master();
        //喂养
        master.feed(dog);
    }
}

运行结果如下图所示:

在这里插入图片描述

以上程序编译和运行都很正常,输出结果也是对的,那么存在什么问题吗?

假设后期用户提出了新的需求,软件可能面临着功能扩展,这个扩展会很方便吗?

假设现在主人家里又来了一个宠物猫,那该怎么办呢?

在以上代码的基础之上,新增了一个Cat类,来表示宠物猫,这个对于程序来说是可以接受的:

//宠物猫

public class Cat {
    String name;
    public Cat(String name){
        this.name = name;
    }
    //吃的行为
    public void eat(){
        System.out.println(this.name + "在吃鱼!");
    }
}

另外,除了增加一个Cat类之外,我们还需要“修改”Master主人类的源代码,这件事儿是我们程序员无法容忍的,因为修改之前写好的源代码就面临着重新编译、重新全方位的测试,这是一个巨大的工作,维护成本很高,也很麻烦:

//主人

public class Master {
    //喂养行为
    public void feed(Dog dog){
        //主人喂养宠物,宠物就吃
        System.out.println("主人开始喂食儿");
        dog.eat();
        System.out.println("主人喂食儿完毕");
    }
    //喂养行为
    public void feed(Cat cat){
        //主人喂养宠物,宠物就吃
        System.out.println("主人开始喂食儿");
        cat.eat();
        System.out.println("主人喂食儿完毕");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //创建狗对象
        Dog dog = new Dog("二哈");
        //创建主人对象
        Master master = new Master();
        //喂养
        master.feed(dog);
        //创建猫对象
        Cat cat = new Cat("汤姆");
        //喂养
        master.feed(cat);
    }
}

运行结果如下图所示:

在这里插入图片描述

以上程序在扩展的过程当中就违背了OCP原则,因为在扩展的过程当中修改了已经写好的Master类,怎样可以解决这个问题呢?多态可以解决,请看代码:

//宠物类 -----》父类

public class Pet {
    String name;
    //吃的行为
    public void eat(){
    }
}

//宠物猫

public class Cat extends Pet{
    public Cat(String name){
        this.name = name;
    }
    //吃的行为
    public void eat(){
        System.out.println(this.name + "在吃鱼!");
    }
}

//宠物狗

public class Dog extends Pet{
    public Dog(String name){
        this.name = name;
    }
    //吃的行为
    public void eat(){
        System.out.println(this.name + "在啃肉骨头!");
    }
}

//主人

public class Master {
    //喂养行为
    public void feed(Pet pet){
        //主人喂养宠物,宠物就吃
        System.out.println("主人开始喂食儿");
        pet.eat();
        System.out.println("主人喂食儿完毕");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //创建狗对象
        Dog dog = new Dog("二哈");
        //创建主人对象
        Master master = new Master();
        //喂养
        master.feed(dog);
        //创建猫对象
        Cat cat = new Cat("汤姆");
        //喂养
        master.feed(cat);
    }
}

在这里插入图片描述

在以上程序中,Master类中的方法feed(Pet pet)的参数类型定义为更加抽象的Pet类型,而不是具体Dog宠物,或者Cat宠物,显然Master类和具体的Dog、Cat类解耦合了,依赖性弱了,这就是我们通常所说的面向抽象编程,尽量不要面向具体编程,面向抽象编程会让你的代码耦合度降低,扩展能力增强,从而符合OCP的开发原则。假如说这会再来一个新的宠物猪呢,我们只需要这样做,新增加一个“宠物猪类”,然后宠物猪类Pig继承宠物类Pet,并重写eat()方法,然后修改一下测试类就行了,整个过程我们是不需要修改Master类的**,只是额外增加了一个新的类:**

public class Pig extends Pet {
    public Pig(String name){
        this.name = name;
    }
    //吃的行为
    public void eat(){
        System.out.println(this.name + "在吃粥!");
    }
}

public class Test {
    public static void main(String[] args) {
        //创建狗对象
        Dog dog = new Dog("二哈");
        //创建主人对象
        Master master = new Master();
        //喂养
        master.feed(dog);
        //创建猫对象
        Cat cat = new Cat("汤姆");
        //喂养
        master.feed(cat);
        //创建宠物猪对象
        Pig pig = new Pig("小猪猪");
        master.feed(pig);
    }
}

在这里插入图片描述

以上程序中到底哪里使用了多态机制呢?请看下图:

在这里插入图片描述

通过以上内容的学习,我们可以看到多态在开发中联合方法覆盖一起使用,可以降低程序的耦合度,提高程序的扩展力。在开发中尽可能面向抽象编程,不要面向具体编程,好比电脑主板和内存条的关系一样,主板和内存条件之间有一个抽象的符合某个规范的插槽,不同品牌的内存条都可以插到主板上使用,2个G的内存条和4个G的内存条都可以插上,但最终的表现结果是不同的,2个G的内存条处理速度慢一些,4个G的快一些,这就是多态,所谓多态就是同一个行为作用到不同的对象上,最终的表现结果是不同的,主要的要求就是对象是可以进行灵活切换的,灵活切换的前提就是解耦合,解耦合依赖多态机制。

二、什么是多态

从上边的的案例当中我们可以看出:

多态是同一个行为具有多个不同表现形式或形态的能力。

三、多态实现的必要条件

1. 子类必须继承父类

2.必须有重写

3. 父类引用指向子类对象------》向上转型

父类

public class Animal {
	public  void  eat() {
		System.out.println("所有的动物都很能吃。。。。。");
	}
	public  void  run() {
		System.out.println("所有的动物都很能吃。。。。。");
	}
}

子类

public class Cat extends Animal{
	public  void  eat() {
		System.out.println("所有的猫杜能吃。。。。。");
	}
	public void jump() {
		// TODO Auto-generated method stub
		System.out.println("所有的猫都能跳。。。。");
	}
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    public void jump(){
        System.out.println("狗一跳一跳");
    }
}

测试类

public class Test {
	public static void main(String[] args) {	
		/*子类自动转父类*/
            Animal animal = new Cat() | new Dog();//多态
            animal.eat();

            /*父类不能自动转子类,需要强制转化*/
            Cat cat = (Cat) animal;
            cat.jump();
		
	}
}

在这里插入图片描述

四、理解方法调用

public class A {
	public String Show(D obj) {
		return "A and D";
	}
	public String Show(A obj) {
		return "A and A";
	}
}

public class B extends A{
	public String Show(Object obj) {
		return "B and B";
	}
	public String Show(A obj) {
		return "B and A";
	}
}

public class C extends B{
}

public class D  extends B{
	
}

测试类:

public class Test {
	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("4----"+a2.Show(b));
		System.out.println("5----"+a2.Show(c));
		System.out.println("6----"+a2.Show(d));
  
		System.out.println("7---"+b.Show(b));
		System.out.println("8---"+b.Show(c));
		System.out.println("9---"+b.Show(d));
		
	}
}

输出结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值