Java面向对象特征3之多态性
1 - 什么是多态
/*
也叫对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
Person[父类] p1 = new Man()[子类];
Person p1 = new Man();
*/
2 - 理解多态性
/*
理解多态性:可以理解为一个事务的多种形态。
*/
3 - 多态性使用
/*
1-前提:
①首先要有类的继承关系
②要有方法的重写
2-多态性的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写的方法
总结:编译,看左边,运行看右边 Person[左边] p1 = new Man()[右边];
3-对象的多态性:只适用于方法,不适用于属性
*/
代码示例
package com.lzh.exer1; import java.sql.Connection; /* * 多态性的使用举例1 */ public class AnimalTest { public static void main(String[] args) { AnimalTest animal = new AnimalTest(); animal.func(new Dog()); animal.func(new Cut()); } public void func(Animal animal) { // Animal animal = new Dog(); 多态性的体现 animal.eat(); animal.shout(); } // 如果没有多态性,省略重载方法 // public void func(Dog dog) { // dog.eat(); // dog.shout(); // } // public void func(Cut cut) { // cut.eat(); // cut.shout(); // } } class Animal{ public void eat() { System.out.println("动物:进食"); } public void shout() { System.out.println("动物:叫"); } } class Dog extends Animal{ @Override public void eat() { // TODO Auto-generated method stub // super.eat(); System.out.println("吃狗粮"); } @Override public void shout() { // TODO Auto-generated method stub // super.shout(); System.out.println("汪汪"); } } class Cut extends Animal{ @Override public void eat() { // TODO Auto-generated method stub // super.eat(); System.out.println("猫吃鱼"); } @Override public void shout() { // TODO Auto-generated method stub // super.shout(); System.out.println("喵喵"); } } /* * 多态性的使用举例2 */ class Order{ public void method(Object object) { // object.xxx } } /* * 多态性的使用举例3 */ class Driver{ public void doData(Connection conn) { // conn = new MySQLConnection(); // 规范的操作数据 //conn.method1(); //conn.method2(); //conn.method3(); } }
4 - 虚拟方法调用
*
5 - 小结:方法的重载与与重写
6 - 面试题:多态是编译时行为还是运行时行为?
import java.util.Random; //面试题:多态是编译时行为还是运行时行为? //证明如下: class Animal { protected void eat() { System.out.println("animal eat food"); } } class Cat extends Animal { protected void eat() { System.out.println("cat eat fish"); } } class Dog extends Animal { public void eat() { System.out.println("Dog eat bone"); } } class Sheep extends Animal { public void eat() { System.out.println("Sheep eat grass"); } } public class InterviewTest { public static Animal getInstance(int key) { switch (key) { case 0: return new Cat (); case 1: return new Dog (); default: return new Sheep (); } } public static void main(String[] args) { int key = new Random().nextInt(3); System.out.println(key); Animal animal = getInstance(key); animal.eat(); } }
/*
结论:多态是运行行为
*/
7 - instanceof 操作符
使用情景:为了避免在向下转型是出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型
8 - 对象类型转换
/*
Person p1 = new Man(); // Person为父类,Man为Person的子类
// p1.earMoney(); Man所特有的方法
// p1.isSmoking = true; Man所特有的属性
①此时p1不能调用子类(Man())所特有的方法、属性:编译时,p1是Person类型
②有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
③如何才能调用子类特有的属性和方法? 使用强制类型转换符
Man m1 = (Man)p1;
m1.earMoney(); // 这时就可以调用Man类所特有的方法和属性
m1.isSmoking();
// 使用强转时,可能出现ClassCastException的异常
④instanceof 关键字的使用
a instanceof A :判断对象a是否是类A的实例。如果是,返回true,如果不是,返回false
if(p1 instanceof Man){
Man m1 = (Man)p1;
...
}
*/
9 - 继承成员变量和继承方法的区别
package com.lzh.exer1; /* * 说明: * 1-若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边 * * 2-对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的相同实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边 */ class Base { int count = 10; public void display() { System.out.println(this.count); } } class Sub extends Base { int count = 20; public void display() { System.out.println(this.count); } } public class FieldMethodTest { public static void main(String[] args) { Sub s = new Sub(); System.out.println(s.count); // 20 s.display(); // 20 Base b = s; // 多态性 System.out.println(b == s); // true System.out.println(b.count); // 10 b.display(); // 20 } }
/*
说明:
1-若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
2-对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的相同实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
*/