宅男知识大补丸 学多态 认包包

java零基础入门-面向对象篇(十)  多态

面向对象的三大特征,封装,继承我们讲完了,这次来讲多态。

多态就是指一个引用变量,在编译时和运行时类型不一样的情况。那我们首先就要搞清楚一个概念,什么是编译时,什么是运行时

其实这个概念我在最开始就讲过,还记不记得我们讲HelloWorld的时候,用命令行工具编译并且运行了一个java类。不记得的赶紧去复习(老规矩 从HelloWorld 开始吧)。

编译时,就是指java文件通过javac编译器,翻译成class文件的过程。这时候还没有开始执行方法,代码没有被加载到内存中,仅仅是做了一个翻译的动作。

运行时,是指程序申请了内存空间,将变量指向的对象放进内存,运行方法的动作。

为什么我们使用eclipse写代码的时候没见使用过javac这个编译器?

其实这就是使用工具写代码的好处,我们不需要手动操作编译的过程,但是我们经常在写代码的时候,工具在某行代码下面画了条红线,告诉我们这里无法编译通过,并且提示我们为什么,这就是在编译前,eclipse做的语法检查。

编译错误

 

那eclipse在什么时候编译java文件呢?我们看看eclipse背着我们做了些什么事

 

eclipse编译的时机

每次写完一段代码,这时eclipse会自动帮我们把写好的代码编译成class文件,而当我们完成了代码,点击运行的时候,这个时候所有的代码都被加载到内存中,这个时候就是运行时。

比如我们运行一个main方法的时候,所有的对象变量都在内存中待着,等候召唤,这个时候就是运行时。

搞清楚了编译时和运行时,我们继续来往下走。

什么是多态

首先我们举个例子帮助我们了解多态的概念。

有一天,你的女王大人说 我要买包包,但是他并没有具体说哪个牌子哪个款式,所以她说的只是一个概念,是父类

Bag bag;  你的女王大人给你定义了一个包,这是编译时。

 

我要买包包

圣旨已下,我们为了让她们开心,必须精挑细选。这里看好了三个包包,定义三个类,每个类都继承Bag类,有自己的价格和描述,最后给女王自己选。

女王只要包,没说具体要什么包,所以我们给的时候只能给包,这个包满足女王的条件即可。所以可以将具体的包(子类)看做是包(父类)的一种,换句话说,就是我们可以将子类看做是一种特殊的父类。

 

多态

当我们确定了两个类的父子关系以后,就可以将一个新创建的子类对象,赋值给父类变量。这时候我们注意看 queen.buyBag(XXX) 这段代码,同样一个对象 queen ,同样调用方法 buyBag ,却打印出了不同的结果,这就表现出了多态的特征。

这里要注意一点,多态是指子类重写了父类的方法后,展现出来的,而不包括成员变量,成员变量是不具备多态性的。

 

成员变量没有多态性

这是什么奇怪的规定?为什么方法具有多态的特征,而成员变量不具有多态的特征呢?

是不是又准备开始死记硬背了?说好的,我们要用理解代替死记硬背。

那么我就用内存图来解释这个奇怪的规定。

内存里的多态

通过内存图看多态,我们前面储备了足够的知识,如果你认真读过我前面的文章,看这个完全没压力。

 

内存图

为什么成员变量没有多态的特性?左边的图大家非常熟悉,就是一个普通的对象创建。

我们看右边,我们讲继承的时候说过,创建子类对象的时候,会自动获得父类的成员变量,会在内存中开辟空间,保存父类的成员变量,用super来访问他们。再看代码,左侧是父类的变量 bag_bv ,他指向哪?他指向子类对象的 super。

好了说到这,肯定又有同学要问,为啥指向super不是指向this?我很喜欢这种打破砂锅问到底的精神。

因为编译时,变量 bay_bv 是父类型,但是他并不知道 “将来” (运行时) 会指向何种子类型的对象,这时候你让他怎么去决定指向那个子类的变量?这不是强人所难么,所以他只能指向将来那个对象的super,通过super找到父类的成员变量,所以成员变量不具备多态的特征。

 

杠精还没下线,那为啥方法不指向父类的方法而是子类的重写的方法呢?

回答这个问题排除2个情况

1.父类没有describe方法,子类有describe方法,这个时候调用的就是子类的方法,没有发生多态。

2.父类有describe方法,子类没有describe方法,这个时候调用的是继承于父类的方法,没有发生多态。

最后就是,父类有方法,子类也有方法,这个时候子类重写了父类的方法。如果是父类变量保持子类对象地址,则发生多态。

发生多态时,就是我们上面讲解的概念,编译时编译的是父类的方法,运行时创建了子类的对象,是运行的子类方法

验证一下 编译时编译的是父类的方法(这里容易绕晕,还是验证一下)

 

编译时编译父类中方法

 

这个时候,首先运行代码左边,Bag bag_bv 这个时候,因为父类和子类都有方法  describe,所以父类完全可以在编译时就确定这个没有问题,编译通过,然后在运行时,使用 bag_bv 这个变量去调用子类的 describe方法,方法展现多态特征。

 

静态成员的多态规则

Bag bag_bv = new BottegaVeneta();

bag_bv.describe();

多态发生在对象调用方法的时候,而静态变量,静态方法属于类,如果 describe 是静态方法,那么使用对象调用方法和使用类调用方法是一样的

bag_bv.describe()    就是   Bag.describe()  

所以静态成员也没有多态,都是调用父类方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值