Java中的 多态 的概念和理解

实现前提:1.要有继承关系       2.要有方法覆盖          3.父类引用指向了子类的实例

1.继承关系好理解,

     有 extends ,对类进行继承(假设 class A extends B{}即A是子类,B是父类,子类拥有父类的所有成员)

2.方法覆盖稍微不好理解,

    首先它的定义是:在子类中替换  父类或祖先类  中的某个方法。

    实现方法:通过子类重新定义 与 父类或祖先类中具有   同样签名  和 返回类型  的方法。

    覆盖的时候要注意访问权限:覆盖后不能比原先的方法的访问权限小(可相等,可大于)

                                权限大小: priavte < default < protected < public

    注意点:

       1.父类中被final修饰的不能被子类覆盖,其他修饰符可以被子类覆盖

       2.只有在子类类体中可以访问到的父类或祖先类才能被覆盖

       3.静态方法不能被覆盖。

       4.构造方法不属于成员,所以也不能被覆盖,也不能被隐藏。

3.父类引用指向子类实例(在main方法中来执行)

     语法:父类类型  a   = new  子类类型();

     理解:1.子类类型可以被看成是父类类型

               2.子类继承父类,子类就拥有了父类的所有成员

    运行时多态的含义:当同一个引用变量(父类引用)指向不同的子类实例,然后访问    引用变量 . 成员方法  ,                                        方法会有不同的 表现

     成员访问的特点:
         成员变量:编译看左边,运行看左边
         成员方法:编译看左边,运行看右边。

         以Person s=new Student();为例。左边用以声明类型,右边用以创建对象。

          而编译器编译时会查看左边的声明中是否有编译错误(在多态中尤为重要,看是否左边的类型中是否缺少右边类型的方法,否则报错。右边的类型通常为左边类型的子类)。

           即使没有报错,一旦右边实际真正运行起来也有可能会出现错误,这时就要查看右边类中具体实现的代码。所以编译时错误看左边,运行时错误看右边。

  一个例子:

  1. //毕业后,找到一份工作,前期买了一辆大众车,实现代码如下:  
  2. public class test{  
  3.     public static void main(String[] args){  
  4.         DZ dz =new DZ("大众");  
  5.         people p =new people();  
  6.         p.drive(dz);  
  7.     }  
  8. }  
  9.   
  10. class people{  
  11.     public String name;  
  12.     public DZ dz;  
  13.     public void drive(DZ dz){  
  14.         this.dz=dz;  
  15.         dz.run();  
  16.     }  
  17. }  
  18.   
  19. class DZ{  
  20.     public String name ;  
  21.       
  22.     public DZ(String name){  
  23.         this.name=name;  
  24.     }  
  25.     public void run(){  
  26.         System.out.print("上海大众在已120迈的速度在跑");  
  27.     }  

  1. //后期如果我有钱以后又买了一辆奔驰,我要换奔驰 ,不用多态的情况下代码如下:  
  2. public class test{  
  3.     public static void main(String[] args){       
  4.         Benz benz=new Benz("奔驰车");  
  5.         people p =new people();  
  6.         p.drive(benz);  
  7.     }  
  8. }  
  9.   
  10. class people{  
  11.     public String name;  
  12.     public DZ dz;  
  13.     public Benz benz;  
  14.       
  15.     public void drive(DZ dz){  
  16.         this.dz=dz;  
  17.         dz.run();  
  18.     }  
  19.       
  20.     public void drive(Benz benz){  
  21.         this.benz=benz;  
  22.         benz.run();  
  23.     }  
  24. }  
  25.   
  26. class DZ{  
  27.     public String name ;  
  28.       
  29.     public DZ(String name){  
  30.         this.name=name;  
  31.     }  
  32.     public void run(){  
  33.         System.out.print(name+"已在路上飞快的奔跑");  
  34.     }  
  35. }  
  36.   
  37. class Benz{  
  38.     public String name;  
  39.     public Benz(String name){  
  40.         this.name=name;  
  41.     }  
  42.     public void run(){  
  43.         System.out.print(name+"已在路上飞快的奔跑");  
  44.     }  
  45.       

  1. //这样是不是程序粘连性太强,不利于扩展,而且Java特性是对扩展开放,对修改关闭 我每换一辆车就需要改代码。  
  2. //那样代码修改太多,也不安全,用了多态以后,效果就很不一样了,妈妈在也不用担心我换车了,so easy!!  
  3. public class test{  
  4.     public static void main(String[] args){       
  5.         Benz benz=new Benz("奔驰车");  
  6.         DZ dz=new DZ("大众车");  
  7.         BMW bmw=new BMW("宝马车");  
  8.         people p =new people();  
  9.         p.drive(benz);  
  10.         p.drive(dz);  
  11.         p.drive(bmw);  
  12.     }  
  13. }  
  14.   
  15. class people{  
  16.     public String name;  
  17.     public Car car;  
  18.       
  19.       
  20.     public void drive(Car car){  
  21.         this.car=car;  
  22.         car.run();  
  23.     }  
  24.       
  25. }  
  26.   
  27. class Car{  
  28.     public String name;  
  29.       
  30.     public Car(String name){  
  31.         this.name=name;  
  32.     }  
  33.       
  34.     public void run(){  
  35.         System.out.println(name+"已在路上飞快的奔跑");  
  36.     }  
  37. }  
  38. class DZ extends Car{  
  39.    public DZ(String name){  
  40.         super(name);  
  41.     }  
  42. }  
  43.   
  44. class Benz extends Car{  
  45.     public Benz(String name){  
  46.         super(name);  
  47.     }  
  48. }  
  49.   
  50. class BMW extends Car{  
  51.     public BMW(String name){  
  52.         super(name);  
  53.     }  
  54.       





深入理解多态执行的时候的编译看左边,运行看右边

      老毕在讲到多态执行问题时,结合下面的例子,给我们总结了一套口诀:“成员变量,静态方法看左边;非静态方法:编译看左边,运行看右边。”意思是:当父类变量引用子类对象时(Fu f = new Zi();

),在这个引用变量f指向的对象中,他的成员变量和静态方法与父类是一致的,他的非静态方法,在编译时是与父类一致的,运行时却与子类一致(发生了复写)。

例:

class Fu {

 intnum = 5;

static void method4() {

 System.out.println("fu method_4");

 }

void method3() {

 System.out.println("fu method_3");

 }

}

class Zi extends Fu {

 intnum = 8;

static void method4() {

 System.out.println("zi method_4");

 }

void method3() {

 System.out.println("zi method_3");

 }

}

class DuoTaiDemo4 {

 public static void main(String[] args) {

Fu f = new Zi();

 System.out.println(f.num);//与父类一致

 f.method4();//与父类一致

 f.method3();//编译时与父类一致,运行时与子类一致

  Ziz = new Zi();

 System.out.println(z.num);

 z.method4();

 z.method3();

 }

}

输出结果:

5

fu method_4

zi method_3

8

zi method_4

zi method_3

 

 

个人分析:

Fu f = new Zi();----------首先了解变量F到底是什么,把这句子分2段:Fu f;这是声明一个变量f为Fu这个类,那么知道了f肯定是Fu类。然后我们f=newZi();中建立一个子类对象赋值给了f,结果是什么??

结果是,拥有了被Zi类函数覆盖后的Fu类对象----f------。

 

-------------------------------------------也就是说:

只有子类的函数覆盖了父类的函数这一个变化,但是f肯定是Fu这个类,也就是说f不可能变成其他比如Zi这个类等等(突然f拥有了Zi类特有函数,成员变量等都是不可能的)。所以f所代表的是函数被复写后(多态的意义)的一个Fu类,而Fu类原来有的成员变量(不是成员函数不可能被复写)没有任何变化----------------获得结论:A:成员变量:编译和运行都看Fu。

但是f的Fu类函数被复写了。--------------获得结论:B:非静态方法:编译看Fu,运行看Zi

对于静态方法:编译和运行都看Fu!!

其实很简单,首先我们要理解静态情况下发生了什么?

----------------当静态时,Fu类的所有函数跟随Fu类加载而加载了。也就是Fu类的函数(是先于对象建立之前就存在了,无法被后出现的Zi类对象所复写的,所以没发生复写,那么获得:C:静态方法:编译和运行都看Fu。


             

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值