多态
概念:指同一操作作用于某一类对象,可以有不同的解释,产生不同的执行结果;
存在的必要条件
① 需要存在继承和实现关系;
② 同样的方法调用而执行不同操作,运行不同代码(重写操作);
③ 在运行时父类或者接口的引用变量可以引用其子类的对象;
作用
① 多态通过分离做什么和怎么做,从另一个角度将接口和实现进行分离;
② “多态”则消除了类型之间耳朵耦合关系;
③ 多态的存在提高了程序的扩展和后期的可维护性;
1 public class AnimalDemo{ 2 public static void main(String []args){ 3 //父类的引用变量可以引用其子类对象
4 Animal animal1=new Dog("旺财"); 5 animal1.eat(); 6
7 Animal animal2=new Cat("招财"); 8 animal2.eat(); 9
10 } 11 } 12
13 class Animal{ 14 private String name; 15 public Animal(String name){ 16 this.name=name; 17 } 18
19 //这是一个通用的方法,实现没有太大的意义 20 //只是告诉其子类去实现它
21 public void eat(){ 22
23 } 24 } 25
26 class Dog extends Animal{ 27 public Dog(String name){ 28 super(name); 29 } 30
31 //对父类的方法进行重写
32 public void eat(){ 33 System.out.println("啃骨头"); 34 } 35 } 36
37 class Cat extends Animal{ 38 public Cat(String name){ 39 super(name); 40 } 41
42 //对父类的方法进行重写
43 public void eat(){ 44 System.out.println("吃鱼"); 45 } 46 }
对象上下转型
① 由子类转型成父类,在继承图上是向上移动的,一般称为向上转型;
② 向上转型是从一个较专用类型像较通用类型转型,所以总是安全的,也就是说,子类是父类的一个超集;
③ 向上转型过程中,类接口中唯一可能发生的事情就是丢失方法,而不是获取方法;
④ 与之相反的操作是向下转型,不安全(可能需要instanceof操作符协助);
⑤ LSP(liskov替换原则):子类型必须能够替换掉它们的基类型;
⑥ 安全的上转和LSP的实施,充分体现继承的“is-a”关系;
上面的demo就是向上转型
1 public class AnimalDemo{ 2 public static void main(String []args){ 3 //父类的引用变量可以引用其子类对象
4 Animal animal1=new Dog("旺财狗");//向上转型 5 //向上转型首先是安全的,但可能会导致子类方法的丢失 6 //父类的引用变量只能调用父类中有的方法,或子类中重写的方法
7 animal1.eat(); 8 //animal1.sleep();//在dog中的特有方法不能使用
9
10 Animal animal2=new Cat("招财猫"); 11 animal2.eat(); 12
13
14 //向下转型是不安全的 15 //Cat cat=(Cat)animal1;//转换异常
16
17 } 18 } 19
20 class Animal{ 21 private String name; 22 public Animal(String name){ 23 this.name=name; 24 } 25
26 //这是一个通用的方法,实现没有太大的意义 27 //只是告诉其子类去实现它
28 public void eat(){ 29
30 } 31 } 32
33 class Dog extends Animal{ 34 public Dog(String name){ 35 super(name); 36 } 37
38 //对父类的方法进行重写
39 public void eat(){ 40 System.out.println("啃骨头"); 41 } 42
43 public void sleep(){ 44 System.out.println("睡觉"); 45 } 46 } 47
48 class Cat extends Animal{ 49 public Cat(String name){ 50 super(name); 51 } 52
53 //对父类的方法进行重写
54 public void eat(){ 55 System.out.println("吃鱼"); 56 } 57 }
instanceof运算符用来在运行时通过返回一个布尔值来指出对象是否是特定类或者是它的子类的一个实例;
用法:
result=object instanceof calss
result:布尔类型
object:必选项,任意对象表达式
class:必选项,任意已定义的对象类
说明:如果object是class或者其子类的一个实例,则instanceof运算符返回true,如果不是或者object是null,则返回false;
典型使用场合:在对对象做下转型之前,没有其它有关对象类型信息时务必使用instanceof来判断一下,以免抛出ClassCastException异常;
1 public class AnimalDemo{ 2 public static void main(String []args){ 3 //父类的引用变量可以引用其子类对象
4 Animal animal1=new Dog("旺财狗");//向上转型 5 //向上转型首先是安全的,但可能会导致子类方法的丢失 6 //父类的引用变量只能调用父类中有的方法,或子类中重写的方法
7 animal1.eat(); 8 //animal1.sleep();//在dog中的特有方法不能使用
9
10 Animal animal2=new Cat("招财猫"); 11 animal2.eat(); 12
13
14 //向下转型是不安全的 15 //Cat cat=(Cat)animal1;//转换异常 16
17 //解决方法
18 if(animal1 instanceof Cat){ 19 //未进入
20 System.out.println("进入执行"); 21 Cat cat=(Cat)animal1; 22 } 23
24 if(animal2 instanceof Cat){ 25 //进入
26 System.out.println("进入执行2"); 27 Cat cat=(Cat)animal2; 28 cat.sleep(); 29 } 30
31 } 32 } 33
34 class Animal{ 35 private String name; 36 public Animal(String name){ 37 this.name=name; 38 } 39
40 //这是一个通用的方法,实现没有太大的意义 41 //只是告诉其子类去实现它
42 public void eat(){ 43
44 } 45 } 46
47 class Dog extends Animal{ 48 public Dog(String name){ 49 super(name); 50 } 51
52 //对父类的方法进行重写
53 public void eat(){ 54 System.out.println("啃骨头"); 55 } 56
57 public void sleep(){ 58 System.out.println("睡觉"); 59 } 60 } 61
62 class Cat extends Animal{ 63 public Cat(String name){ 64 super(name); 65 } 66
67 //对父类的方法进行重写
68 public void eat(){ 69 System.out.println("吃鱼"); 70 } 71
72 public void sleep(){ 73 System.out.println("睡觉"); 74 } 75 }
动态绑定和静态绑定
概念:
① 在程序执行前方法以及被绑定,针对Java简单的可以理解为程序编译期的绑定(静态绑定)java当中的方法是final,static,private和构造方法都是前期绑定的;
② 运行时,根据变量实际引用的对象类型决定调用哪个方法(动态绑定);
静态绑定在编译期进行
Person.sayHi();
动态绑定在运行期进行
Person p=new Teacher();
p.sayHi();
多态的概念基于对象引用的动态绑定特性;
多态应用
简单来说,多态是具有表现多种行为能力的特征;
同一个实现接口,使用不同的实例而执行不同操作;
不使用多态:
1 public class PrinterDemo{ 2 public static void main(String []args){ 3 ColorPrinter cp=new ColorPrinter("惠普"); 4 BlackPrinter bp=new BlackPrinter("戴尔"); 5 School school=new School(); 6 //school.setColorPrinter(cp);
7 school.setBlackPrinter(bp);//新建的黑白打印时,要修改学习的打印方法
8 school.print("hello java"); 9
10 /*以上每次调用不同的子类时特别麻烦,会影响到其他类中的代码修改*/
11 } 12 } 13
14 class Printer{ 15 private String brand; 16
17 public Printer(String brand){ 18 this.brand=brand; 19 } 20
21 public String getBrand() 22 { 23 return brand; 24 } 25
26 //打印方法应该由其子类来具体的实现
27 public void print(String content){ 28
29 } 30 } 31
32
33 //开原原则:对修改是封闭的,对扩展是开放的 34 //可以使用多态解决这个问题,父类的引用变量可以引用其子类的对象
35 class School{ 36 private ColorPrinter cp=null; 37 private BlackPrinter bp=null; 38 private ZhenPrinter bp=null; 39
40 //安装彩色打印机
41 public void setColorPrinter(ColorPrinter cp){ 42 this.cp=cp; 43 } 44
45 //安装黑白打印机
46 public void setBlackPrinter(BlackPrinter bp){ 47 this.bp=bp; 48 } 49
50 //安装针式打印机
51 public void setZhenPrinter(ZhenPrinter bp){ 52 this.bp=bp; 53 } 54
55 public void print(String content){ 56 //交给中心所安装的彩色打印机来打印 57 //cp.print(content); 58 //交给中心所安装的黑白打印机来打印
59 bp.print(content); 60 } 61
62 } 63
64 class ColorPrinter extends Printer{ 65 public ColorPrinter(String brand){ 66 super(brand); 67 } 68 //对父类的方法进行重写
69 public void print(String content){ 70 System.out.println(getBrand()+"彩色打印:"+content); 71 } 72 } 73
74 class BlackPrinter extends Printer{ 75 public BlackPrinter(String brand){ 76 super(brand); 77 } 78 //对父类的方法进行重写
79 public void print(String content){ 80 System.out.println(getBrand()+"黑白打印:"+content); 81 } 82 } 83
84 class ZhenPrinter extends Printer{ 85 public ZhenPrinter(String brand){ 86 super(brand); 87 } 88 //对父类的方法进行重写
89 public void print(String content){ 90 System.out.println(getBrand()+"针式打印:"+content); 91 } 92 }
使用多态:
1 public class PrinterDemo{ 2 public static void main(String []args){ 3 ColorPrinter cp=new ColorPrinter("惠普"); 4 BlackPrinter bp=new BlackPrinter("戴尔"); 5 ZhenPrinter zp=new ZhenPrinter("戴尔"); 6 School school=new School(); 7
8 school.setPrinter(zp);//这里的参数可以调用较灵活,使用cp,bp,zp都可以,而不用改school类中的方法
9 school.print("hello java"); 10
11 } 12 } 13
14 class Printer{ 15 private String brand; 16
17 public Printer(String brand){ 18 this.brand=brand; 19 } 20
21 public String getBrand() 22 { 23 return brand; 24 } 25
26 //打印方法应该由其子类来具体的实现
27 public void print(String content){ 28
29 } 30 } 31
32
33 //开原原则:对修改是封闭的,对扩展是开放的 34 //可以使用多态解决这个问题,父类的引用变量可以引用其子类的对象
35 class School{ 36 private Printer p=null;//安装打印机 37
38 //拿父类的引用变量作为参数,好处就是可以接受任何其子类的对象 39 //越是抽象的东西就是越稳定的
40 public void setPrinter(Printer p){ 41 this.p=p; 42 } 43
44 public void print(String content){ 45 //交给中心所安装的打印机来打印
46 p.print(content); 47 } 48 } 49
50 class ColorPrinter extends Printer{ 51 public ColorPrinter(String brand){ 52 super(brand); 53 } 54 //对父类的方法进行重写
55 public void print(String content){ 56 System.out.println(getBrand()+"彩色打印:"+content); 57 } 58 } 59
60 class BlackPrinter extends Printer{ 61 public BlackPrinter(String brand){ 62 super(brand); 63 } 64 //对父类的方法进行重写
65 public void print(String content){ 66 System.out.println(getBrand()+"黑白打印:"+content); 67 } 68 } 69
70 class ZhenPrinter extends Printer{ 71 public ZhenPrinter(String brand){ 72 super(brand); 73 } 74 //对父类的方法进行重写
75 public void print(String content){ 76 System.out.println(getBrand()+"针式打印:"+content); 77 } 78 }