Java多态


多态可以简单理解为一个父类可以引用不同的子类,官方一点的说就是同一个行为具有多个不同表现形式或形态的能力。在代码运行时,使用不同的实例会执行不同的操作。多态可以基于继承实现也可以基于接口实现,关于继承和接口大家可以看这里

链接: https://blog.csdn.net/weixin_56680764/article/details/125521355

一、多态的实现条件

接下来我们就从多态实现的三个必要条件来了解一下多态

1、继承

在多态中必须存在子类和父类的继承关系

2、重写

就是要在子类中对父类的某些方法进行重新定义,在调用这些方法时就会调用子类的方法。当我们使用多态方式调用方法时,首先会检查父类中是否有该方法,如果有才会去调用子类的同名方法;如果没有就会报错。

3、父类引用指向子类对象

也就是要对子类做向上转型,向上转型:将子类的引用赋给父类对象,只有这样该引用才能调用父类的方法和子类的方法。(但是父类类型的引用只能调用在父类中定义的属性和方法,对于只存在于子类中的方法和属性就不能调用了)

Parent p=new Child();

4、代码实现

接下来咱们还是先看代码,概念太抽象了,咱们可以从代码中理解

class Animal{
	public void eat() {
		System.out.println("动物要吃东西");
		play();
	}
	public void play() {
		System.out.println("动物吃完东西要玩");
	}
}
class Dog extends Animal{
	public void fight() {
		System.out.println("狗狗要打架哎");
		play();
	}
	/**
	 * 子类重写了父类的 paly 方法
	 * 指向子类的父类引用调用 play()时,就会调用子类的此方法
	 */
	public void play() {
		System.out.println("狗狗还要玩!");
	}
}

public class Test1 {
	public static void main(String[] args) {
		Animal dog=new Dog();
		dog.eat();
	}
}

运行结果如下:
动物要吃东西
狗狗还要玩!

由运行结果可以看出来,dog.eat()首先是运行父类中的 eat()方法,然后再运行子类中的 paly()方法。因为子类中没有重写父类中的 eat()方法,所以指向 Dog 的 Animal 类型引用时会调用父类的eat()方法;而子类重写了父类的 play() 方法,那么指向 Dog 的 Animal 类型引用会调用子类Dog中的 play() 方法。

二、多态的优点

1、消除类型之间的耦合关系(这个不是很好解释,简单来说就是有了多态,你改了一个地方那个的代码,其他地方不用做修改),还是写一段代码来理解一下吧

首先是使用多态的

class Animal{
	public void eat() {
		System.out.println("动物要吃东西");
	}
}
class Dog extends Animal{
	public void eat() {
		System.out.println("狗狗要吃饭");
	}
}
class Cat extends Animal{
	public void eat() {
		System.out.println("猫咪要吃饭");
	}
}
class Horse extends Animal{
	public void eat() {
		System.out.println("马儿要吃饭");
	}
}
public class Test1 {
	public static void main(String[] args) {
		Animal dog=new Dog();
		dog.eat();
		Animal cat=new Cat();
		cat.eat();
		Animal horse=new Horse();
		horse.eat();
	}
}

运行结果如下:
狗狗要吃饭
猫咪要吃饭
马儿要吃饭

接下来是不使用多态的:

class Animal{
	public void eat() {
		System.out.println("动物要吃东西");
	}
}
class Dog extends Animal{
	public void eat() {
		System.out.println("狗狗要吃饭");
	}
}
class Cat extends Animal{
	public void eat() {
		System.out.println("猫咪要吃饭");
	}
}
class Horse extends Animal{
	public void eat() {
		System.out.println("马儿要吃饭");
	}
}
public class Test1 {
	public static void main(String[] args) {
		Animal animal=new Dog();
		animal.eat();
		animal=new Cat();
		animal.eat();
		animal=new Horse();
		animal.eat();
	}
}

运行结果如下:
狗狗要吃饭
猫咪要吃饭
马儿要吃饭
可以看出运行结果都是一样的,但是不使用多态的话,如果把 animal 改成其他的,后边的代码就都要作出改动。

2.灵活性、简化性、接口性、可替换性

三、经典实例

这个例子是摘自: http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx

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(B 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));      
    }
}

运行结果如下:
1–A and A
2–A and A
3–A and D
4–B and A
5–B and A
6–A and D
7–B and B
8–B and B
9–A and D

分析多态时,我们始终要记住一句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的。
继承中对对象方法的调用存在一个优先级:this.show(obj) super.show(obj) this.show((super)obj) super.show((super)obj)
我们可以分析一下上边的第四个输出 a2.show(b)。这里 a2 是引用变量,A为类型,他的引用对象是B。因此按照上面那句话的意思是说有B来决定调用谁的方法,所以a2.show(b)应该要调用B中的show(B obj),产生的结果应该是“B and B”,但是为什么会与前面的运行结果产生差异呢?这里我们忽略了后面那句话“但是这儿被调用的方法必须是在超类中定义过的”,那么show(B obj)在A类中不存在,所以不会去调用它。根据继承的调用方法的优先级可以确认,调用A类中的show(A obj)。(因为这里的 this 就是指A)。这样的话,前四个输出就都可以解释了。

接下来我们解释第五个,a2.show©,a2是A类型的引用变量,所以this就代表了A,a2.show©,它在A类中找发现没有找到,于是到A的超类中找(super),由于A没有超类(Object除外),所以跳到第三级,也就是this.show((super)O),C的超类有B、A,所以(super)O为B、A,this同样是A,这里在A中找到了show(A obj),同时由于a2是B类的一个引用且B类重写了show(A obj),因此最终会调用子类B类的show(A obj)方法,结果也就是B and A。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cw旧巷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值