黑马软件工程师——Java基础-多态
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
1、概念
一个对象拥有多个状态。
2、多态的三要素
(1):继承、实现
(2):方法重写、
(3):父类引用指向子类对象
3、多态存在时对于成员(成员属性、成员静态、非静态方法)的调用问题
3.1 成员属性的调用
在这里前往不要去别什么看左边,看右边之类的话,面试紧张极其容易忘记(回忆高中物理的左右手定则)我对于这一块的理解有一个方法,提出来供各位博友参考,如有不对,还请指正,毕竟我也是正在学习之中。
我们知道对于子类构建对象时,首先会调用父类的构造方法。所以我在这里理解子类对象由两部分构成:父类对象、子类特有对象。如下图1-1。
如果我们利用父类引用指向子类对象那个,然后利用引用变量调用成员属性,当然这个属性如果是子类特有属性,一定会编译错误,告诉你无法识别;如果你调用的是父类的成员属性,编译通过,运行正常。代码如下:其中Animal 为父类,Cat继承Animal,num1为animal中定义的一个属性。
1 Animal a = new Cat();
2 System.out.println(a.num1);
这种报错的结果是什么呢?因为我们知道首先定义a 为一个Animal类型的变量,所以虽然赋给其一个Cat类型的变量,可是只能看到上图中父类对象包含的那个属性和方法。父类属性中肯定找不到子类特有对象num1。
3.2 成员方法的调用
3.2.1非静态方法的调用
还是首先看图1-1。这里我需要说明子类特有成员方法指的是子类新定义,而没有在父类中出现过的方法。父类方法包括父类定义的方法和子类重写父类的方法(这里可以将重写理解为将方法体改变,而方法定义没动,就像租房子,换的是房客,房子永远在哪里,一动不动。所以方法原来在父类对象中,重写之后还是在父类对象中)。 如过我们利用父类引用变量调用父类的方法,那么如果方法经过重写,就调用的是重写过后的方法,如果没有经过重写,那肯定还是父类中的方法,如果调用子类特有的方法,那一定会报错。代码如下。
其中eat()方法在子类Cat中重写,sleep()为父类定义的非静态方法。function()方法为子类Cat的特有方法。
1 Animal a = new Cat();
2 a.eat();3 a.sleep() 4 a.function();
原因是什么呢?跟上面的成员属性一模一样。变量a 为父类类型,即使你传给的是Cat类型,他也只能看到父类对象的成员方法。无法看到子类对象特有的方法。
3.3.2 静态方法调用
因为静态存储于方法去,而不在上面的子类对象所属的堆内存区。所以静态方法这里只需要记住一定,那就是静态与对象无关,只与类有关。是个什么类的引用变量,调用的就是那个类中的方法。当然这里所说的是子类重写了这个静态方法。代码如下:其中sleep()是静态方法,这个调用的一定是父类中未重写的方法。
1 Animal a = new Cat();
2 a.sleep();
总结:大家只需要记住那个图就行。用文字表达就是子类对象由父类对象和子类特有对象构成。利用父类引用类型变量来调用方法时,其能看到只有父类中的属性和方法(重写方法也子啊这里)。
引申:如果还需要理解更清楚还有一点就是如果父类和子类中同时拥有一个相同名字的成员变量,如果利用父类的引用变量调用,调用的是父类中的属性,这个利用上面的知识点好像清楚。可是利用子类调用,调用的就是子类中的特有变量。有的人无法理解为什么在子类对象中存在两个名字一样的成员变量,凭什么用子类变量调用时,就需要调用子类特有的属性呢?这两个属性都属于子类对象呀。我们可以这样理解,那就是子类特有对象的优先级高于父类,虚拟机会首先在子类特有对象中去寻找,找到了就不在继续寻找。当寻找子类重写的方法时,在子类特有的方法中无法找到,就去父类对象中寻找。
以下是所以得代码和运行结果:
1 /*
2 这篇博客就是为了阐述清楚多态中对于成员的调用问题
3 */
4 class Animal{
5 int num = 1;
6 void sleep(){
7 System.out.println("I am sleeping");
8 }
9 void eat( ){
10 System.out.println("Animal loves eating meat");
11 }
12 static void breath(){
13 System.out.println("Animal breath");
14 }
15 }
16 class Cat extends Animal{
17 int num1 = 10;
18 void eat( ){
19 System.out.println("Cat loves eating mouse");
20 }
21 static void breath(){
22 System.out.println("Cat breathes quietly");
23 }
24 void function(){
25 System.out.println("Cat enjoys people");
26 }
27 }
28 class Dog extends Animal{
29 int num = 100;
30 void eat( ){
31 System.out.println("Dog loves eating bone");
32 }
33 static void breath(){
34 System.out.println("Dog breathes loudly");
35 }
36 void function(){
37 System.out.println("Dog defend our wealth");
38 }
39 }
40 class DemoPolymorphism{
41 public static void main(String[]args){
42 Animal a = new Cat(); //这个使用父类引用变量调用成员变量
43 System.out.println(a.num); //这个使用父类引用变量调用子类重写的方法
44 a.eat(); //这个使用父类引用变量调用子类静态方法
45 a.breath(); //这个使用父类引用变量调用子类调用子类特有方法
46 //a.function();
47 Dog d = new Dog(); //使用子类引用变量调用子类父类均有的属性
48 System.out.println(d.num); //用子类引用变量调用子类重写的方法
49 d.eat(); //用子类引用变量调用静态的方法
50 d.breath(); //用子类引用变量调用子类继承的方法
51 d.sleep();
52 }
53 }