java多态的理解(运行时多态)

说道多态,一定离不开其它两大特性:封装和继承。而多态是在它们的基础之上表现而来的,息息相关。在记忆中,每一次学习面向对象的时候,都与这三大特性有扯不开的关系,多态是面向对象的重点,也算是难点。

是什么?

文学角度:一千个读者就有一千零一个哈姆雷特;

公司主管角度:老板交代下来相同任务,每个人完成的情况不同;

专业角度:同种类的多个对象,在接收到同一个消息时却产生了不同反应和效果

从代码形式上看: 父类的对象变量调用了子类中重写的方法(注意: 往往是有一个父类,而他有多个子类,且在这些子类中同时重写父类的某个方法);

结论:多态的前提是有一个父类,多个子类。

 

做什么?

 

父类的对象变量可以引用本类的对象,也可以引用子类的对象。

           由于Object类是超根类(祖先类),因此,它的对象变量可以引用所有类的对象。

           特殊运算符: instanceof 属性

           注意: 子类的对象变量可以引用父类的对象吗? 

           答案: 不可以

           若要进行,则必须强制转换。

即对象类型的转换分为以下两种:

           1) 向上转型: 子类的对象可以直接赋给父类的对象变量。 

这种现象也称之为类型的自动转换。 

           2) 向下转型:  将父类的引用强制转换成子类的引用。 

注意: 它必须强制转换。

              格式:  (类型名) 对象变量;

当父类对象变量引用了子类的对象时,则问: 父类的对象变量是否可以直接调用子类的特有方法?

           答案: 否定的。

           例如: Animal 是父类,  Dog是子类,  而getName()方法是Dog子类特有的方法。

                    因此,   当有 Anaimal  a = new Dog(); 时,

                    则 a.getName(); 是否正确? 

                    答: 错误。  

           问: 那如何访问?

           答: 需要先强制转换(向下转型)

              子类类名   对象变量 = (子类类名)父类的对象变量;

              即:   Dog d = (Dog)a;

              之后,  d.getName(); 此时,正确。

什么情况下需要将对象的引用实现强制转换(还原)(向下转型)?

           1) 一定是发生多态:

              父类的对象变量引用了子类的对象。

              Object obj = new Student();

           2)一定是想要去访问(调用)子类对象的特有属性或方法。

              父类的对象变量.子类对象的特有方法(属性);  //则错了。

              Stringstr = obj.getSchool();  //错了。 

              ((子类类名)父类的对象变量).子类对象的特有方法(属性); //则对了。

              Stringstr = ((Student)obj).getSchool();  //对了。

  //多态: 父类的对象变量引用了子类的对象。

<span style="font-size:18px;"><span style="font-size:18px;">public class AnimalsTest {
	public static void main(String[] args) {
		Animal a = new Animal("动物");
		
		Dog d1 = new Dog("狗", "旺财", true, 2);
		Cat c1 = new Cat("猫", "豆豆", "blue");
		
		System.out.println( a );
		System.out.println( d1 );
		System.out.println( c1 );
		
		boolean flag = a instanceof Animal ; //判断a属于Animal类型吗
		System.out.println( flag );
		
		flag = a instanceof Dog;
		System.out.println( flag );
		
		flag = d1 instanceof Dog;
		System.out.println( flag );
		
		flag = d1 instanceof Animal;  //当结果为true时,说明它们之间存在继承关系。
		System.out.println( flag );
		
		//多态: 父类的对象变量引用了子类的对象。
		Animal a1 = new Dog("狗", "ABC", false, 3);
		//System.out.println( a1.getName() ); //调用a1的 getName()方法. 此时,它会去Animal类中找 getName()方法。若找不到,则报错。
	
		//判断a1是否拥有Dog类的特性,若有,则还原。
		if( a1 instanceof Dog ){
			Dog dd = (Dog)a1; //将a1强制转换为Dog类型。
			System.out.println( dd.getName() );
		}
		
		System.out.println("程序结束。");
	}
}
</span></span>

干什么?

 

在调用一个方法时,从源代码上看,无法确定调用了哪个对象的方法。只有在程序运行期间根据对象变量引用的实际对象才能确定此方法是

哪个对象的。这种现象称之为动态绑定 (联编)。

结论: 动态绑定的前提是:

1) 发生继承,且一个父类有多个子类。

2) 在每一个子类中对继承自父类的同一个方法实现了重写。

3) 发生多态,即: 父类对象变量引用了不同的子类对象。

4) 父类的对象变量调用了重写的方法,即: 发生了动态绑定。从而实现了多的价值。

为什么?

关于面向对象的三大特性,为了更好地理解我们为什么要用它,很有必要知道它带来的好处。当然,站在巨人的肩膀上学习总是高效的,分享一下:

封装性: 安全性和重用性。

继承性: 高效性和重用性。

多态性: 统一性(有机性)和高效性。

对于这三大特性的理解不同,可能会有不同的体会,例如:大自然不同的风景呈现,我们享受到的也不同,如果每天都面对着同一幅场景,后果是很可怕的。要想更好的理解,不断地实践是很不错的选择呢!

 

业务思想

 

学习的目的是为了更好地实践,要想在不断进行的项目中可以完成的更好、更为的轻松,这是离不开多态的。我们可以从最后一个demo中,看出加上动态绑定的图形选择,可以很有效的避免我们敲出很多图形的初始化代码,很高效,而且重复的初始化图形,很容易把我们惹毛的(当然这是开玩笑的),而我们要做的就是,尽量减少我们的工作负担,更为高效、轻松的完成。

多态,你一生都离不开的两个字,无论在哪里。

---------------------------------------------------------------------------------------------------------------------------------------------------------------

多态有编译时多态 和运行时多态。
第一个是通过方法重载实现;第二个是通过方法覆盖实现(子类覆盖父类方法)。
第一种就是我们调用方法是不用区分参数类型,程序会自动执行相应方法,如: 加法运算,可以使int相加,可以是double相加,都是同一个方法名。
第二种就是动态绑定,使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。 这样的作用就是扩展性极好,玩过网游的话应该知道 游戏中有不同的角色,它们都有一个父类,它们做相同动作时表现出来的效果就会不一样,比如跑,魔法师的跑跟战士的跑就不会一样,这就是俩者都覆盖了父类中的跑方法,各自有自己的现实,表现出来多态。 如果有一天你想再加个角色,只用再写一个类继承该父类,覆盖其中的跑方法就行了,其他代码不用怎么改,所以可维护性也很好。

这一个小的程序 或许你体会不到多态的强度作用。其实说到多态就是 面向接口编程,它不和具体类尽心挂钩了
比如 你没用多态的话 ,
你没实例化一个对象 就要new一下,那假如你那天改变了需求了呢?那是不是又要改里面的?这样不好,所以 你可以通过多态,把需要相似的给提出来,然后继承它 这样 以后需要扩展你仅仅只是继承而已。这样就很简单。

这个需要多看代码 才可以更深刻理解。假设有一个类 叫 鸟类,它拥有属性翅膀,拥有方法鸣叫,如下
public class Bird{
private Wing wing;
public void moo(){
System.out.println("鸟叫声");
}
}
鸟类封装了 翅膀类和moo方法;另外有两个类都继承鸟类并重写了moo方法,分别是鹦鹉和麻雀如下:
鹦鹉类:
public class Parrot extends Bird{
public void moo(){
System.out.println("鹦鹉的叫声");
}
}
麻雀类:
public class Sparrow extends Bird{
public void moo(){
System.out.println("麻雀的叫声");
}
}
方法重写应该懂吧,不懂自己找书看吧;然后你有个妻子她想听鸟叫,就有个妻子类
public class Wife{
public void listen(Bird bird){
bird.moo();
}
/*这时多态就很好的体现了,你妻子想听鸟叫,无论什么鸟都可以给她,但是你想让她和鹦鹉
*说话,你就买了一只鹦鹉传给listen方法,结果你妻子听到了鹦鹉的叫声,程序输出:鹦
*鹉的叫声
*/
public static void main(String[] args) {
new Wife().listen(new Parrot());
}
}
多态实现了动态绑定,让程序有了很好的扩展性,比如你以后想买一只燕子送给你妻子,就只需要写个燕子类Swallow继承Bird方法就可以了,而不需要再在妻子类里添加一个方法listen(Swallow swallow)……上面编码没用编译器,可能有错误,请谅解

 

  • 81
    点赞
  • 246
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值