Java中的多态性

Java有三大特性:封装、继承和多态

所谓多态就是指有多个状态,比如“食物”这个概念,它可以是肉、鱼和蔬菜,因此“食物”具有多态性。在程序的运行时有多个状态,也就是父类的引用变量被哪个子类所实例化,这就是向上转型。多态实现的三个必要条件:继承、重写、向上转型。

继承:继承就是一个父类有多个子类,比如一个Food类可以有Meet类和Fish类。

重写:重写很关键,就是子类中必须重写父类的方法,这样在向上转型后的调用中才能调用不同子类中的方法。

向上转型:父类的引用变量被子类所实例化,如Food f = new Meet。向上转型会造成一些方法和属性的丢失,他可以调用所有父类中的的属性和方法,但不能调用只存在于子类中的类型和方法。

【1】多态的使用规则

【2】基于继承的多态

【3】基于接口的多态

【4】多态的扩展


多态的使用规则

子类的父类引用向上转型,只能访问父类的属性和方法,不能访问只存在于子类的方法,重载也不可以,必须重写才可以调用子类中方法和属性,(重载是返回相同,参数个数不同。重写是返回和参数都相同)也就是子类中重写了父类中的方法时,调用时肯定调用子类中的方法。

基于继承的多态

基于继承的多态表现为一个或者多个子类对父类方法的重写,子类对象向上转型之后可以调用子类中这些重写的方法。下面是基于继承的例子:

package TwoWeek;

public class Extend1{
	public static void main(String args[]){
		Food f1 = new Food();
		f1.Eat();
		Food f2 = new Meet();
		f2.Eat();
		Food f3 = new Fish();
		f3.Eat();
		//f3.HaveBone();// 使用Food中没有的方法会出错
	}
}

class Food{
	Food(){
		System.out.println("这是Food的构造方法");
	}
	public void Eat(){
		System.out.println("吃食物");
	}
}


class Meet extends Food{
	public void Eat(){
		System.out.println("我们逮肉");
	}
}


class Fish extends Food{
	public void Eat(){
		System.out.println("我们吃鱼");
	}

	public void HaveBone(){
		System.out.println("鱼是有刺的");
	}
}

输出结果为:

这是Food的构造方法
吃食物
这是Food的构造方法
我们逮肉
这是Food的构造方法
我们吃鱼

在向上转型的之后,调用各自子类中的Eat()方法。


基于接口的多态

接口的多态和集成的多态是相似的,用几个不同的类来实现接口并覆盖接口中的同一方法,继承只有单继承,而接口不同,可以实现多继承,所以其有更高的灵活性。

package TwoWeek;

public class Extend2{
	public static void main(String args[]){
		Meet1 f2 = new Meet1();
		f2.Eat();
		Fish1 f3 = new Fish1();
		f3.Eat();
		f3.HaveBone();// 我们发现这个是可以不会报错的
	}
}

interface Food1{
	public void Eat();
}

class Meet1 implements Food1{
	public void Eat(){
		System.out.println("我们逮肉");
	}
}


class Fish1 implements Food1{
	public void Eat(){
		System.out.println("我们吃鱼");
	}

	public void HaveBone(){
		System.out.println("鱼是有刺的");
	}
}

输出结果为:

<span style="font-size:18px;">这是Food的构造方法
吃食物
这是Food的构造方法
我们逮肉
这是Food的构造方法
我们吃鱼</span><span style="color:#3333ff;font-size:24px; font-weight: bold;">
</span>

多态的扩展

当父类对象的引用变量引用子类对象时,被应用对象而不是引用变量决定了调用谁的成员方法,但是这边被调用的方法是在子类中定义过的,也就是被子类重写的方法,根据调用链中调用方法的优先级来确认方法。下面是引用自大神博客http://blog.csdn.net/chenssy/article/details/12786385的经典继承例子:

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  
确实是从第四个开始就迷糊了,下面来捋一捋。

下面我们来分析第四个a2.show(b),其中a2是A类型的引用变量,也就是父类中的引用变量,引用的是B类型的对象,也就是应该调用b类中的show(B obj)方法,出现"B and B"的结果,当不能忘了一件事,该show()方法必须在类中也存在且被子类覆写才可以,但是父类中没有存在。那就只能按照继承链总的的调用优先级来执行了,优先级是这样的(this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O))所有才会在A类中找到show(A obj),又因为B类中覆写了show(A obj),所以最终调用B类中的方法。


在分析一下第五个,便于加深理解,a2.show(c),a2是A类型,所以this = A,因为引用的也是B类型对象,所以首先也在B里边找,没有找到。然后到this也就是A里边找,发现又没有找到,然后按照规定就到A的super类里边找,但是A没有超类,那就按照第三继承规则this.show((super)O),C的超类为A,且this是A,所以a.show(a),有因为B中覆写了它,所以结果还是B and A.



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值