J2SE——多态的浅析

java语言的思想就是面向对象,我们学习面向对象的特点之一继承时会学习都一个非常重要的概念,多态。而且会一直伴随着我们之后的学习直到工作当中,下面是多态的一些浅见,希望对您有所帮助。


多态(polymorphism)的概念  一个对象变量可以指向多种实际类型的现象。


多态分两种:
编译时多态:编译时动态重载; Ainmal ainmal = new Dog();
②运行时多态:指一个对象可以具有多个类型。 ainmal.sleep();


对象是客观的,人对对象的认识是主观的。
例:
Animal a=new Dog();查看格式名称;(编译时看左边,运行时看右边)
Dog d=(Dog)a。声明父类来引用子类。(强制转换)


运行时多态的三原则:(应用时为覆盖)
1、对象不变;(改变的是主观认识)
2、对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型一定要为运行时类型的父类(或者同类型)。
对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。属性看父类,方法看子类.
3、在程序的运行时,动态类型判定。运行时调用运行时类型,即它调用覆盖后的方法。


关系运算符:instanceof
a  instanceof Animal;(这个式子的结果是一个布尔表达式)
a为对象变量,Animal是类名。
上面语句是判定a是否可以贴Animal标签。如果可以贴则返回true,否则返回false。
在上面的题目中: a instanceof Animal返回 True,
                 a instanceof Dog也返回 True,
instanceof用于判定是否将前面的对象变量赋值后边的类名。
Instanceof一般用于在强制类型转换之前判定变量是否可以强制转换。
如果Animal a=new Animal();
Dog d= (Dog)a;
此时编译无误,但运行则会报错。


Animal a=new Dog()相当于下面语句的功能:
Animal a=getAnimal();
Public static Animal.getAnimal(){


Return new Dog();
}




1、静态多态(方法重载)
2、动态多态(基于继承)---->引用多态




下面这个例子,大家可以先不看下面的答案,在自己脑海中运行一道,看看自己想的跟实际结果是否相符。
java 代码
public class Polymorphism{   
 public static void main(String[] args) {   
   A b = new B();   
   b.fb();   
 }   
}   
  
class A {   
 public A(){   
 }   
 public void fa() {   
    System.out.println("CLASS A :Function fa Runing......");   
 }   
  
 public void fb() {   
    System.out.println("CLASS A :Function fb Runing......");   
    fa();   
    System.out.println("CLASS A :Function fb Stop......");   
 }   
}   
  
class B extends A {   
 public B(){   
 }   
 public void fa() {   
    System.out.println("CLASS B :Function fa Runing......");   
 }   
  
 public void fb() {   
    System.out.println("CLASS B :Function fb Runing......");   
    super.fb();   
    System.out.println("CLASS B :Function fb Stop......");   
  }   
}  


下面是它的运行结果:
CLASS B :Function fb Runing......
CLASS A :Function fb Runing......
CLASS B :Function fa Runing......
CLASS A :Function fb Stop......
CLASS B :Function fb Stop......


梳理一下程序流程:
   1、运行main函数,创建B对象,调用B的方法fb,于是打印出"CLASS B :Function fb Runing......",都在情理之中。
   2、执行super.fb(),调用父类A的方法fb,首先打印出"CLASS A :Function fb Runing......",预料之中
   3、执行方法fa(),打印出"CLASS B :Function fa Runing......",呃?奇怪了,为什么不是执行A的方法fa(),而是子类B中的fa()呢?当前被执行的是类A的方法,那么虚拟机找到的应该是A类的Method Table,找到的应该是A类的方法fa()啊?难解~
   4、打印"CLASS A :Function fb Stop......",返回
   5、打印"CLASS A :Function fb Stop.....",返回,程序结束。
  现在问题清楚了,就是虚拟机在执行类A方法的时候查找的Method Table竟然是子类B的。为什么呢?其实,只要我们清楚java方法调用的方式,这个问题就迎刃而解了。在Java虚拟机中,每启动一个新的线程,虚拟机都会为它分配一个Java栈,而每当线程调用一个java方法时,虚拟机就会在该线程的java栈中压入一个新帧,用以存储参数,局部变量等数据。我们将这个正在被执行的方法称为该线程的当前方法,其相应的栈帧为当前帧。
    当我们调用一个方法时,我们需要往当前帧中压入哪些参数?在Java中,所有的实例方法(Instance Method)调用的时候都会把当前对象压入当前帧中,Java虚拟机正是通过这个参数来决定当前所使用的类(通过判断该对象的类型)。
    在上面的例子中,main中调用b.fb()时,压入的当前对象自然是B类对象,我们记为b。在B的fb()中调用super.fb()时,压入的就是刚刚压入的对象,也就是b了。同样,在A的fb中调用fa()时,压入的也是b。因此,在使用 invokevirtual指令调用fa()时,找的就是B的方法表(当前对象b的类型为B),也就执行了类B的fa了。
    这种现象在构造函数中特别常见,因为构造函数中会隐含使用调用父类的构造函数的,如果在父类的构造函数中调用了实例方法(如 A的fa),而在子类中又覆盖了这个实例方法(如 B的fa),那么得到的结果往往不是我们所要的。因此,我们最好不要在构造函数中使用多态方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值